Fix:core:Add comments and some #defines for constants
[profile/ivi/navit.git] / navit / navit / map / binfile / binfile.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 <stdlib.h>
21 #include <glib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <math.h>
25 #include "config.h"
26 #include "debug.h"
27 #include "plugin.h"
28 #include "projection.h"
29 #include "item.h"
30 #include "map.h"
31 #include "maptype.h"
32 #include "attr.h"
33 #include "coord.h"
34 #include "transform.h"
35 #include "file.h"
36 #include "zipfile.h"
37 #include "linguistics.h"
38 #include "endianess.h"
39 #include "callback.h"
40 #include "types.h"
41
42 static int map_id;
43
44
45 /**
46  * @brief A map tile, a rectangular region of the world.
47  *
48  * Represents a "map tile", a rectangular region of the world. The
49  * binfile format divides the world into tiles of different sizes for
50  * easy handling.
51  * A binfile is a ZIP archive; each member file (with the exception of
52  * index files) represents one tile. The data from a tile file is read
53  * into memory and used directly as the tile data of this struct.
54  * <p>
55  * See the Navit wiki for details on the binfile format:
56  *
57  * http://wiki.navit-project.org/index.php/Navit%27s_binary_map_driver
58  * <p>
59  * Note that this tile struct also maintains pointers to several current positions
60  * inside the tile. These are not part of the actual tile data, but are
61  * used for working with the data.
62  */
63 struct tile {
64         int *start;             //!< Memory address of the buffer containing the tile data (the actual map data).
65         int *end;               //!< First memory address not belonging to the tile data.
66                                 /**< Thus tile->end - tile->start represents the size of the tile data
67                                  * in multiples of 4 Bytes.
68                                  */
69         int *pos;               //!< Pointer to current position (start of current item) inside the tile data.
70         int *pos_coord_start;   //!< Pointer to the first element inside the current item that is a coordinate.
71                                 /**< That is the first position after the header of an
72                                  * item. The header holds 3 entries each 32bit wide integers:
73                                  * header[0] holds the size of the whole item (excluding this size field)
74                                  * header[1] holds the type of the item
75                                  * header[2] holds the size of the coordinates in the tile
76                                  */
77         int *pos_coord;         //!< Current position in the coordinates region of the current item.
78         int *pos_attr_start;    //!< Pointer to the first attr data structure of the current item.
79         int *pos_attr;          //!< Current position in the attr region of the current item.
80         int *pos_next;          //!< Pointer to the next item (the item which follows the "current item" as indicated by *pos).
81         struct file *fi;        //!< The file from which this tile was loaded.
82         int zipfile_num;
83         int mode;
84 };
85
86
87 struct map_download {
88         int state;
89         struct map_priv *m;
90         struct map_rect_priv *mr;
91         struct file *http,*file;
92         int zipfile,toffset,tlength,progress,read,dl_size;
93         long long offset,start_offset,cd1offset,size;
94         struct zip64_eoc *zip64_eoc;
95         struct zip64_eocl *zip64_eocl;
96         struct zip_eoc *zip_eoc;
97         struct zip_cd *cd_copy,*cd;
98 };
99
100 /**
101  * @brief Represents the map from a single binfile.
102  *
103  */
104 struct map_priv {
105         int id;
106         char *filename;              //!< Filename of the binfile.
107         char *cachedir;
108         struct file *fi,*http;
109         struct file **fis;
110         struct zip_cd *index_cd;
111         int index_offset;
112         int cde_size;
113         struct zip_eoc *eoc;
114         struct zip64_eoc *eoc64;
115         int zip_members;
116         unsigned char *search_data;
117         int search_offset;
118         int search_size;
119         int version;
120         int check_version;
121         int map_version;
122         GHashTable *changes;
123         char *passwd;
124         char *map_release;
125         int flags;
126         char *url;
127         int update_available;
128         char *progress;
129         struct callback_list *cbl;
130         struct map_download *download;
131         int redirect;
132         long download_enabled;
133 };
134
135 struct map_rect_priv {
136         int *start;
137         int *end;
138         enum attr_type attr_last;
139         int label;
140         int *label_attr[5];
141         struct map_selection *sel;
142         struct map_priv *m;
143         struct item item;
144         int tile_depth;
145         struct tile tiles[8];
146         struct tile *t;
147         int country_id;
148         char *url;
149         struct attr attrs[8];
150         int status;
151 #ifdef DEBUG_SIZE
152         int size;
153 #endif
154 };
155
156 /**
157  * @brief Represents a search on a map.
158  * This struct represents a search on a map; it is created
159  * when starting a search, and is used for retrieving results.
160  */
161 struct map_search_priv {
162         struct map_priv *map;
163         struct map_rect_priv *mr;
164         struct map_rect_priv *mr_item;
165         struct item *item;
166         struct attr *search;
167         struct map_selection ms;
168         int partial;
169         int mode;
170         GHashTable *search_results;
171 };
172
173
174 static void push_tile(struct map_rect_priv *mr, struct tile *t, int offset, int length);
175 static void setup_pos(struct map_rect_priv *mr);
176 static void map_binfile_close(struct map_priv *m);
177 static int map_binfile_open(struct map_priv *m);
178 static void map_binfile_destroy(struct map_priv *m);
179
180 static void lfh_to_cpu(struct zip_lfh *lfh) {
181         dbg_assert(lfh != NULL);
182         if (lfh->ziplocsig != zip_lfh_sig) {
183                 lfh->ziplocsig = le32_to_cpu(lfh->ziplocsig);
184                 lfh->zipver    = le16_to_cpu(lfh->zipver);
185                 lfh->zipgenfld = le16_to_cpu(lfh->zipgenfld);
186                 lfh->zipmthd   = le16_to_cpu(lfh->zipmthd);
187                 lfh->ziptime   = le16_to_cpu(lfh->ziptime);
188                 lfh->zipdate   = le16_to_cpu(lfh->zipdate);
189                 lfh->zipcrc    = le32_to_cpu(lfh->zipcrc);
190                 lfh->zipsize   = le32_to_cpu(lfh->zipsize);
191                 lfh->zipuncmp  = le32_to_cpu(lfh->zipuncmp);
192                 lfh->zipfnln   = le16_to_cpu(lfh->zipfnln);
193                 lfh->zipxtraln = le16_to_cpu(lfh->zipxtraln);
194         }       
195 }
196
197 static void cd_to_cpu(struct zip_cd *zcd) {
198         dbg_assert(zcd != NULL);
199         if (zcd->zipcensig != zip_cd_sig) {
200                 zcd->zipcensig = le32_to_cpu(zcd->zipcensig);
201                 zcd->zipccrc   = le32_to_cpu(zcd->zipccrc);
202                 zcd->zipcsiz   = le32_to_cpu(zcd->zipcsiz);
203                 zcd->zipcunc   = le32_to_cpu(zcd->zipcunc);
204                 zcd->zipcfnl   = le16_to_cpu(zcd->zipcfnl);
205                 zcd->zipcxtl   = le16_to_cpu(zcd->zipcxtl);
206                 zcd->zipccml   = le16_to_cpu(zcd->zipccml);
207                 zcd->zipdsk    = le16_to_cpu(zcd->zipdsk);
208                 zcd->zipint    = le16_to_cpu(zcd->zipint);
209                 zcd->zipext    = le32_to_cpu(zcd->zipext);
210                 zcd->zipofst   = le32_to_cpu(zcd->zipofst);
211         }
212 }
213
214 static void eoc_to_cpu(struct zip_eoc *eoc) {
215         dbg_assert(eoc != NULL);
216         if (eoc->zipesig != zip_eoc_sig) {
217                 eoc->zipesig   = le32_to_cpu(eoc->zipesig);
218                 eoc->zipedsk   = le16_to_cpu(eoc->zipedsk);
219                 eoc->zipecen   = le16_to_cpu(eoc->zipecen);
220                 eoc->zipenum   = le16_to_cpu(eoc->zipenum);
221                 eoc->zipecenn  = le16_to_cpu(eoc->zipecenn);
222                 eoc->zipecsz   = le32_to_cpu(eoc->zipecsz);
223                 eoc->zipeofst  = le32_to_cpu(eoc->zipeofst);
224                 eoc->zipecoml  = le16_to_cpu(eoc->zipecoml);
225         }
226 }
227
228 static void binfile_check_version(struct map_priv *m);
229
230 static struct zip_eoc *
231 binfile_read_eoc(struct file *fi)
232 {
233         struct zip_eoc *eoc;
234         eoc=(struct zip_eoc *)file_data_read(fi,fi->size-sizeof(struct zip_eoc), sizeof(struct zip_eoc));
235         if (eoc) {
236                 eoc_to_cpu(eoc);
237                 dbg(1,"sig 0x%x\n", eoc->zipesig);
238                 if (eoc->zipesig != zip_eoc_sig) {
239                         dbg(0,"eoc signature check failed: 0x%x vs 0x%x\n",eoc->zipesig,zip_eoc_sig);
240                         file_data_free(fi,(unsigned char *)eoc);
241                         eoc=NULL;
242                 }
243         }
244         return eoc;
245 }
246
247 static struct zip64_eoc *
248 binfile_read_eoc64(struct file *fi)
249 {
250         struct zip64_eocl *eocl;
251         struct zip64_eoc *eoc;
252         eocl=(struct zip64_eocl *)file_data_read(fi,fi->size-sizeof(struct zip_eoc)-sizeof(struct zip64_eocl), sizeof(struct zip64_eocl));
253         if (!eocl)
254                 return NULL;
255         dbg(1,"sig 0x%x\n", eocl->zip64lsig);
256         if (eocl->zip64lsig != zip64_eocl_sig) {
257                 file_data_free(fi,(unsigned char *)eocl);
258                 dbg(1,"eocl wrong\n");
259                 return NULL;
260         }
261         eoc=(struct zip64_eoc *)file_data_read(fi,eocl->zip64lofst, sizeof(struct zip64_eoc));
262         if (eoc) {
263                 if (eoc->zip64esig != zip64_eoc_sig) {
264                         file_data_free(fi,(unsigned char *)eoc);
265                         dbg(1,"eoc wrong\n");
266                         eoc=NULL;
267                 }
268                 dbg(1,"eoc64 ok 0x%Lx 0x%Lx\n",eoc->zip64eofst,eoc->zip64ecsz);
269         }
270         file_data_free(fi,(unsigned char *)eocl);
271         return eoc;
272 }
273
274 static int
275 binfile_cd_extra(struct zip_cd *cd)
276 {
277         return cd->zipcfnl+cd->zipcxtl;
278 }
279
280 static struct zip_cd *
281 binfile_read_cd(struct map_priv *m, int offset, int len)
282 {
283         struct zip_cd *cd;
284         long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst;
285         if (len == -1) {
286                 cd=(struct zip_cd *)file_data_read(m->fi,cdoffset+offset, sizeof(*cd));
287                 cd_to_cpu(cd);
288                 len=binfile_cd_extra(cd);
289                 file_data_free(m->fi,(unsigned char *)cd);
290         }
291         cd=(struct zip_cd *)file_data_read(m->fi,cdoffset+offset, sizeof(*cd)+len);
292         if (cd) {
293                 dbg(1,"cd at "LONGLONG_FMT" %d bytes\n",cdoffset+offset, sizeof(*cd)+len);
294                 cd_to_cpu(cd);
295                 dbg(1,"sig 0x%x\n", cd->zipcensig);
296                 if (cd->zipcensig != zip_cd_sig) {
297                         file_data_free(m->fi,(unsigned char *)cd);
298                         cd=NULL;
299                 }
300         }
301         return cd;
302 }
303
304 /**
305  * @brief Get the ZIP64 extra field data corresponding to a zip central
306  * directory header.
307  *
308  * @param cd pointer to zip central directory structure
309  * @return pointer to ZIP64 extra field, or NULL if not available
310  */
311 static struct zip_cd_ext *
312 binfile_cd_ext(struct zip_cd *cd)
313 {
314         struct zip_cd_ext *ext;
315         if (cd->zipofst != zip_size_64bit_placeholder)
316                 return NULL;
317         if (cd->zipcxtl != sizeof(*ext))
318                 return NULL;
319         ext=(struct zip_cd_ext *)((unsigned char *)cd+sizeof(*cd)+cd->zipcfnl);
320         if (ext->tag != zip_extra_header_id_zip64 || ext->size != 8)
321                 return NULL;
322         return ext;
323 }
324
325 /**
326  * @param cd pointer to zip central directory structure
327  * @return Offset of local file header in zip file.
328  * Will use ZIP64 data if present.
329  */
330 static long long
331 binfile_cd_offset(struct zip_cd *cd)
332 {
333         struct zip_cd_ext *ext=binfile_cd_ext(cd);
334         if (ext)
335                 return ext->zipofst;
336         else
337                 return cd->zipofst;
338 }
339
340 static struct zip_lfh *
341 binfile_read_lfh(struct file *fi, long long offset)
342 {
343         struct zip_lfh *lfh;
344
345         lfh=(struct zip_lfh *)(file_data_read(fi,offset,sizeof(struct zip_lfh)));
346         if (lfh) {
347                 lfh_to_cpu(lfh);
348                 if (lfh->ziplocsig != zip_lfh_sig) {
349                         file_data_free(fi,(unsigned char *)lfh);
350                         lfh=NULL;
351                 }
352         }
353         return lfh;
354 }
355
356 static unsigned char *
357 binfile_read_content(struct map_priv *m, struct file *fi, long long offset, struct zip_lfh *lfh)
358 {
359         struct zip_enc *enc;
360         unsigned char *ret=NULL;
361
362         offset+=sizeof(struct zip_lfh)+lfh->zipfnln;
363         switch (lfh->zipmthd) {
364         case 0:
365                 offset+=lfh->zipxtraln;
366                 ret=file_data_read(fi,offset, lfh->zipuncmp);
367                 break;
368         case 8:
369                 offset+=lfh->zipxtraln;
370                 ret=file_data_read_compressed(fi,offset, lfh->zipsize, lfh->zipuncmp);
371                 break;
372         case 99:
373                 if (!m->passwd)
374                         break;
375                 enc=(struct zip_enc *)file_data_read(fi, offset, sizeof(*enc));
376                 offset+=lfh->zipxtraln;
377                 switch (enc->compress_method) {
378                 case 0:
379                         ret=file_data_read_encrypted(fi, offset, lfh->zipsize, lfh->zipuncmp, 0, m->passwd);
380                         break;
381                 case 8:
382                         ret=file_data_read_encrypted(fi, offset, lfh->zipsize, lfh->zipuncmp, 1, m->passwd);
383                         break;
384                 default:
385                         dbg(0,"Unknown encrypted compression method %d\n",enc->compress_method);
386                 }
387                 file_data_free(fi, (unsigned char *)enc);
388                 break;
389         default:
390                 dbg(0,"Unknown compression method %d\n", lfh->zipmthd);
391         }
392         return ret;
393 }
394
395 static int
396 binfile_search_cd(struct map_priv *m, int offset, char *name, int partial, int skip)
397 {
398         int size=4096;
399         int end=m->eoc64?m->eoc64->zip64ecsz:m->eoc->zipecsz;
400         int len=strlen(name);
401         long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst;
402         struct zip_cd *cd;
403 #if 0
404         dbg(0,"end=%d\n",end);
405 #endif
406         while (offset < end) {
407                 cd=(struct zip_cd *)(m->search_data+offset-m->search_offset);
408                 if (! m->search_data || 
409                       m->search_offset > offset || 
410                       offset-m->search_offset+sizeof(*cd) > m->search_size ||
411                       offset-m->search_offset+sizeof(*cd)+cd->zipcfnl+cd->zipcxtl > m->search_size
412                    ) {
413 #if 0
414                         dbg(0,"reload %p %d %d\n", m->search_data, m->search_offset, offset);
415 #endif
416                         if (m->search_data)
417                                 file_data_free(m->fi,m->search_data);
418                         m->search_offset=offset;
419                         m->search_size=end-offset;
420                         if (m->search_size > size)
421                                 m->search_size=size;
422                         m->search_data=file_data_read(m->fi,cdoffset+m->search_offset,m->search_size);
423                         cd=(struct zip_cd *)m->search_data;
424                 }
425 #if 0
426                 dbg(0,"offset=%d search_offset=%d search_size=%d search_data=%p cd=%p\n", offset, m->search_offset, m->search_size, m->search_data, cd);
427                 dbg(0,"offset=%d fn='%s'\n",offset,cd->zipcfn);
428 #endif
429                 if (!skip && 
430                     (partial || cd->zipcfnl == len) &&
431                     !strncmp(cd->zipcfn, name, len)) 
432                         return offset;
433                 skip=0;
434                 offset+=sizeof(*cd)+cd->zipcfnl+cd->zipcxtl+cd->zipccml;
435 ;
436         }
437         return -1;
438 }
439
440 static void
441 map_destroy_binfile(struct map_priv *m)
442 {
443         dbg(1,"map_destroy_binfile\n");
444         if (m->fi)
445                 map_binfile_close(m);
446         map_binfile_destroy(m);
447 }
448
449 static void
450 binfile_coord_rewind(void *priv_data)
451 {
452         struct map_rect_priv *mr=priv_data;
453         struct tile *t=mr->t;
454         t->pos_coord=t->pos_coord_start;
455 }
456
457 static int
458 binfile_coord_get(void *priv_data, struct coord *c, int count)
459 {
460         struct map_rect_priv *mr=priv_data;
461         struct tile *t=mr->t;
462         int max,ret=0;
463         max=(t->pos_attr_start-t->pos_coord)/2;
464         if (count > max)
465                 count=max;
466 #if __BYTE_ORDER == __LITTLE_ENDIAN
467         memcpy(c, t->pos_coord, count*sizeof(struct coord));
468 #else
469         {
470                 int i=0,end=count*sizeof(struct coord)/sizeof(int);
471                 int *src=(int *)t->pos_coord;
472                 int *dst=(int *)c;
473                 while (i++ < end) {
474                         *dst++=le32_to_cpu(*src);
475                         src++;
476                 }
477         }
478 #endif
479         t->pos_coord+=count*2;
480         ret=count;
481         return ret;
482 }
483
484 /**
485  * @brief
486  * @param
487  * @return
488  */
489 static void
490 binfile_attr_rewind(void *priv_data)
491 {
492         struct map_rect_priv *mr=priv_data;
493         struct tile *t=mr->t;
494         t->pos_attr=t->pos_attr_start;
495         mr->label=0;
496         memset(mr->label_attr, 0, sizeof(mr->label_attr));
497         
498 }
499
500 static char *
501 binfile_extract(struct map_priv *m, char *dir, char *filename, int partial)
502 {
503         char *full,*fulld,*sep;
504         unsigned char *start;
505         int len,offset=m->index_offset;
506         struct zip_cd *cd;
507         struct zip_lfh *lfh;
508         FILE *f;
509
510         for (;;) {
511                 offset=binfile_search_cd(m, offset, filename, partial, 1);
512                 if (offset == -1)
513                         break;
514                 cd=binfile_read_cd(m, offset, -1);
515                 len=strlen(dir)+1+cd->zipcfnl+1;
516                 full=g_malloc(len);
517                 strcpy(full,dir);
518                 strcpy(full+strlen(full),"/");
519                 strncpy(full+strlen(full),cd->zipcfn,cd->zipcfnl);
520                 full[len-1]='\0';
521                 fulld=g_strdup(full);
522                 sep=strrchr(fulld, '/');
523                 if (sep) {
524                         *sep='\0';
525                         file_mkdir(fulld, 1);
526                 }
527                 if (full[len-2] != '/') {
528                         lfh=binfile_read_lfh(m->fi, binfile_cd_offset(cd));
529                         start=binfile_read_content(m, m->fi, binfile_cd_offset(cd), lfh);
530                         dbg(0,"fopen '%s'\n", full);
531                         f=fopen(full,"w");
532                         fwrite(start, lfh->zipuncmp, 1, f);
533                         fclose(f);
534                         file_data_free(m->fi, start);
535                         file_data_free(m->fi, (unsigned char *)lfh);
536                 }
537                 file_data_free(m->fi, (unsigned char *)cd);
538                 g_free(fulld);
539                 g_free(full);
540                 if (! partial)
541                         break;
542         }
543         
544         return g_strdup_printf("%s/%s",dir,filename);
545 }
546
547 static int
548 binfile_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
549 {       
550         struct map_rect_priv *mr=priv_data;
551         struct tile *t=mr->t;
552         enum attr_type type;
553         int i,size;
554
555         if (attr_type != mr->attr_last) {
556                 t->pos_attr=t->pos_attr_start;
557                 mr->attr_last=attr_type;
558         }
559         while (t->pos_attr < t->pos_next) {
560                 size=le32_to_cpu(*(t->pos_attr++));
561                 type=le32_to_cpu(t->pos_attr[0]);
562                 if (type == attr_label) 
563                         mr->label=1;
564                 if (type == attr_house_number)
565                         mr->label_attr[0]=t->pos_attr;
566                 if (type == attr_street_name)
567                         mr->label_attr[1]=t->pos_attr;
568                 if (type == attr_street_name_systematic)
569                         mr->label_attr[2]=t->pos_attr;
570                 if (type == attr_district_name && mr->item.type < type_line)
571                         mr->label_attr[3]=t->pos_attr;
572                 if (type == attr_town_name && mr->item.type < type_line)
573                         mr->label_attr[4]=t->pos_attr;
574                 if (type == attr_type || attr_type == attr_any) {
575                         if (attr_type == attr_any) {
576                                 dbg(1,"pos %p attr %s size %d\n", t->pos_attr-1, attr_to_name(type), size);
577                         }
578                         attr->type=type;                        
579                         if (ATTR_IS_GROUP(type)) {
580                                 int i=0;
581                                 int *subpos=t->pos_attr+1;
582                                 int size_rem=size-1;
583                                 i=0;
584                                 while (size_rem > 0 && i < 7) {
585                                         int subsize=le32_to_cpu(*subpos++);
586                                         int subtype=le32_to_cpu(subpos[0]);
587                                         mr->attrs[i].type=subtype;
588                                         attr_data_set_le(&mr->attrs[i], subpos+1);
589                                         subpos+=subsize;
590                                         size_rem-=subsize+1;
591                                         i++;
592                                 }
593                                 mr->attrs[i].type=type_none;
594                                 mr->attrs[i].u.data=NULL;
595                                 attr->u.attrs=mr->attrs;
596                         } else {
597                                 attr_data_set_le(attr, t->pos_attr+1); 
598                                 if (type == attr_url_local) {
599                                         g_free(mr->url);
600                                         mr->url=binfile_extract(mr->m, mr->m->cachedir, attr->u.str, 1);
601                                         attr->u.str=mr->url;
602                                 }
603                                 if (type == attr_flags && mr->m->map_version < 1) 
604                                         attr->u.num |= AF_CAR;
605                         }
606                         t->pos_attr+=size;
607                         return 1;
608                 } else {
609                         t->pos_attr+=size;
610                 }
611         }
612         if (!mr->label && (attr_type == attr_any || attr_type == attr_label)) {
613                 for (i = 0 ; i < sizeof(mr->label_attr)/sizeof(int *) ; i++) {
614                         if (mr->label_attr[i]) {
615                                 mr->label=1;
616                                 attr->type=attr_label;
617                                 attr_data_set_le(attr,mr->label_attr[i]+1);
618                                 return 1;
619                         }
620                 }
621         }
622         return 0;
623 }
624
625 struct binfile_hash_entry {
626         struct item_id id;
627         int flags;
628         int data[0];
629 };
630
631 static guint
632 binfile_hash_entry_hash(gconstpointer key)
633 {
634         const struct binfile_hash_entry *entry=key;
635         return (entry->id.id_hi ^ entry->id.id_lo);
636 }
637
638 static gboolean
639 binfile_hash_entry_equal(gconstpointer a, gconstpointer b)
640 {
641         const struct binfile_hash_entry *entry1=a,*entry2=b;
642         return (entry1->id.id_hi==entry2->id.id_hi && entry1->id.id_lo == entry2->id.id_lo);
643 }
644
645 static int *
646 binfile_item_dup(struct map_priv *m, struct item *item, struct tile *t, int extend)
647 {
648         int size=le32_to_cpu(t->pos[0]);
649         struct binfile_hash_entry *entry=g_malloc(sizeof(struct binfile_hash_entry)+(size+1+extend)*sizeof(int));
650         void *ret=entry->data;
651         entry->id.id_hi=item->id_hi;
652         entry->id.id_lo=item->id_lo;
653         entry->flags=1;
654         dbg(0,"id 0x%x,0x%x\n",entry->id.id_hi,entry->id.id_lo);
655         
656         memcpy(ret, t->pos, (size+1)*sizeof(int));
657         if (!m->changes) 
658                 m->changes=g_hash_table_new_full(binfile_hash_entry_hash, binfile_hash_entry_equal, g_free, NULL);
659         g_hash_table_replace(m->changes, entry, entry);
660         dbg(0,"ret %p\n",ret);
661         return ret;
662 }
663
664 static int
665 binfile_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode)
666 {
667         struct map_rect_priv *mr=priv_data;
668         struct tile *t=mr->t,*tn,new;
669         int i,delta,move_len;
670         int write_offset,move_offset,aoffset,coffset,clen;
671         int *data;
672
673         {
674                 int *i=t->pos,j=0;
675                 dbg(0,"Before: pos_coord=%d\n",t->pos_coord-i);
676                 while (i < t->pos_next) 
677                         dbg(0,"%d:0x%x\n",j++,*i++);
678                 
679         }
680         aoffset=t->pos_attr-t->pos_attr_start;
681         coffset=t->pos_coord-t->pos_coord_start-2;
682         clen=t->pos_attr_start-t->pos_coord+2;
683         dbg(0,"coffset=%d clen=%d\n",coffset,clen);
684         switch (mode) {
685         case change_mode_delete:
686                 if (count*2 > clen)
687                         count=clen/2;
688                 delta=-count*2;
689                 move_offset=coffset+count*2;
690                 move_len=t->pos_next-t->pos_coord_start-move_offset;
691                 write_offset=0;
692                 break;
693         case change_mode_modify:
694                 write_offset=coffset;
695                 if (count*2 > clen) {
696                         delta=count*2-clen;
697                         move_offset=t->pos_attr_start-t->pos_coord_start;
698                         move_len=t->pos_next-t->pos_coord_start-move_offset;
699                 } else {
700                         move_len=0;
701                         move_offset=0;
702                         delta=0;
703                 }
704                 break;
705         case change_mode_prepend:
706                 delta=count*2;
707                 move_offset=coffset-2;
708                 move_len=t->pos_next-t->pos_coord_start-move_offset;
709                 write_offset=coffset-2;
710                 break;
711         case change_mode_append:
712                 delta=count*2;
713                 move_offset=coffset;
714                 move_len=t->pos_next-t->pos_coord_start-move_offset;
715                 write_offset=coffset;
716                 break;
717         default:
718                 return 0;
719         }
720         dbg(0,"delta %d\n",delta);
721         data=binfile_item_dup(mr->m, &mr->item, t, delta > 0 ? delta:0);
722         data[0]=cpu_to_le32(le32_to_cpu(data[0])+delta);
723         data[2]=cpu_to_le32(le32_to_cpu(data[2])+delta);
724         new.pos=new.start=data;
725         new.zipfile_num=t->zipfile_num;
726         new.mode=2;
727         push_tile(mr, &new, 0, 0);
728         setup_pos(mr);
729         tn=mr->t;
730         tn->pos_coord=tn->pos_coord_start+coffset;
731         tn->pos_attr=tn->pos_attr_start+aoffset;
732         dbg(0,"moving %d ints from offset %d to %d\n",move_len,tn->pos_coord_start+move_offset-data,tn->pos_coord_start+move_offset+delta-data);
733         memmove(tn->pos_coord_start+move_offset+delta, tn->pos_coord_start+move_offset, move_len*4);
734         {
735                 int *i=tn->pos,j=0;
736                 dbg(0,"After move: pos_coord=%d\n",tn->pos_coord-i);
737                 while (i < tn->pos_next) 
738                         dbg(0,"%d:0x%x\n",j++,*i++);
739         }
740         if (mode != change_mode_append)
741                 tn->pos_coord+=move_offset;
742         if (mode != change_mode_delete) {
743                 dbg(0,"writing %d ints at offset %d\n",count*2,write_offset+tn->pos_coord_start-data);
744                 for (i = 0 ; i < count ; i++) {
745                         tn->pos_coord_start[write_offset++]=c[i].x;
746                         tn->pos_coord_start[write_offset++]=c[i].y;
747                 }
748                         
749         }
750         {
751                 int *i=tn->pos,j=0;
752                 dbg(0,"After: pos_coord=%d\n",tn->pos_coord-i);
753                 while (i < tn->pos_next) 
754                         dbg(0,"%d:0x%x\n",j++,*i++);
755         }
756         return 1;
757 }
758
759 static int
760 binfile_attr_set(void *priv_data, struct attr *attr, enum change_mode mode)
761 {
762         struct map_rect_priv *mr=priv_data;
763         struct tile *t=mr->t,*tn,new;
764         int offset,delta,move_len;
765         int write_offset,move_offset,naoffset,coffset,oattr_len;
766         int nattr_size,nattr_len,pad;
767         int *data;
768
769         {
770                 int *i=t->pos,j=0;
771                 dbg(0,"Before: pos_attr=%d\n",t->pos_attr-i);
772                 while (i < t->pos_next) 
773                         dbg(0,"%d:0x%x\n",j++,*i++);
774                 
775         }
776
777         write_offset=0; 
778         naoffset=t->pos_attr-t->pos_attr_start;
779         coffset=t->pos_coord-t->pos_coord_start;
780         offset=0;
781         oattr_len=0;
782         if (!naoffset) {
783                 if (mode == change_mode_delete || mode == change_mode_modify) {
784                         dbg(0,"no attribute selected\n");
785                         return 0;
786                 }
787                 if (mode == change_mode_append)
788                         naoffset=t->pos_next-t->pos_attr_start;
789         }
790         while (offset < naoffset) {
791                 oattr_len=le32_to_cpu(t->pos_attr_start[offset])+1;
792                 dbg(0,"len %d\n",oattr_len);
793                 write_offset=offset;
794                 offset+=oattr_len;
795         }
796         move_len=t->pos_next-t->pos_attr_start-offset;
797         move_offset=offset;
798         switch (mode) {
799         case change_mode_delete:
800                 nattr_size=0;
801                 nattr_len=0;
802                 pad=0;
803                 break;
804         case change_mode_modify:
805         case change_mode_prepend:
806         case change_mode_append:
807                 nattr_size=attr_data_size(attr);
808                 pad=(4-(nattr_size%4))%4;
809                 nattr_len=(nattr_size+pad)/4+2;
810                 if (mode == change_mode_prepend) {
811                         move_offset=write_offset;
812                         move_len+=oattr_len;
813                 }
814                 if (mode == change_mode_append) {
815                         write_offset=move_offset;
816                 }
817                 break;
818         default:
819                 return 0;
820         }
821         if (mode == change_mode_delete || mode == change_mode_modify) 
822                 delta=nattr_len-oattr_len;
823         else
824                 delta=nattr_len;
825         dbg(0,"delta %d oattr_len %d nattr_len %d\n",delta,oattr_len, nattr_len);
826         data=binfile_item_dup(mr->m, &mr->item, t, delta > 0 ? delta:0);
827         data[0]=cpu_to_le32(le32_to_cpu(data[0])+delta);
828         new.pos=new.start=data;
829         new.zipfile_num=t->zipfile_num;
830         new.mode=2;
831         push_tile(mr, &new, 0, 0);
832         setup_pos(mr);
833         tn=mr->t;
834         tn->pos_coord=tn->pos_coord_start+coffset;
835         tn->pos_attr=tn->pos_attr_start+offset;
836         dbg(0,"attr start %d offset %d\n",tn->pos_attr_start-data,offset);
837         dbg(0,"moving %d ints from offset %d to %d\n",move_len,tn->pos_attr_start+move_offset-data,tn->pos_attr_start+move_offset+delta-data);
838         memmove(tn->pos_attr_start+move_offset+delta, tn->pos_attr_start+move_offset, move_len*4);
839         if (mode != change_mode_append)
840                 tn->pos_attr+=delta;
841         {
842                 int *i=tn->pos,j=0;
843                 dbg(0,"After move: pos_attr=%d\n",tn->pos_attr-i);
844                 while (i < tn->pos_next) 
845                         dbg(0,"%d:0x%x\n",j++,*i++);
846         }
847         if (nattr_len) {
848                 int *nattr=tn->pos_attr_start+write_offset;
849                 dbg(0,"writing %d ints at %d\n",nattr_len,nattr-data);
850                 nattr[0]=cpu_to_le32(nattr_len-1);
851                 nattr[1]=cpu_to_le32(attr->type);
852                 memcpy(nattr+2, attr_data_get(attr), nattr_size);
853                 memset((unsigned char *)(nattr+2)+nattr_size, 0, pad);
854         }
855         {
856                 int *i=tn->pos,j=0;
857                 dbg(0,"After: pos_attr=%d\n",tn->pos_attr-i);
858                 while (i < tn->pos_next) 
859                         dbg(0,"%d:0x%x\n",j++,*i++);
860         }
861         return 1;
862 }
863
864 static struct item_methods methods_binfile = {
865         binfile_coord_rewind,
866         binfile_coord_get,
867         binfile_attr_rewind,
868         binfile_attr_get,
869         NULL,
870         binfile_attr_set,
871         binfile_coord_set,
872 };
873
874 static void
875 push_tile(struct map_rect_priv *mr, struct tile *t, int offset, int length)
876 {
877         dbg_assert(mr->tile_depth < 8);
878         mr->t=&mr->tiles[mr->tile_depth++];
879         *(mr->t)=*t;
880         mr->t->pos=mr->t->pos_next=mr->t->start+offset;
881         if (length == -1)
882                 length=le32_to_cpu(mr->t->pos[0])+1;
883         if (length > 0) 
884                 mr->t->end=mr->t->pos+length;
885 }
886
887 static int
888 pop_tile(struct map_rect_priv *mr)
889 {
890         if (mr->tile_depth <= 1)
891                 return 0;
892         if (mr->t->mode < 2)
893                 file_data_free(mr->m->fi, (unsigned char *)(mr->t->start));
894 #ifdef DEBUG_SIZE
895 #if DEBUG_SIZE > 0
896         dbg(0,"leave %d\n",mr->t->zipfile_num);
897 #endif
898 #endif
899         mr->t=&mr->tiles[--mr->tile_depth-1];
900         return 1;
901 }
902
903
904 static int
905 zipfile_to_tile(struct map_priv *m, struct zip_cd *cd, struct tile *t)
906 {
907         char buffer[1024];
908         struct zip_lfh *lfh;
909         char *zipfn;
910         struct file *fi;
911         dbg(1,"enter %p %p %p\n", m, cd, t);
912         dbg(1,"cd->zipofst=0x%Lx\n", binfile_cd_offset(cd));
913         t->start=NULL;
914         t->mode=1;
915         if (m->fis)
916                 fi=m->fis[cd->zipdsk];
917         else
918                 fi=m->fi;
919         lfh=binfile_read_lfh(fi, binfile_cd_offset(cd));
920         zipfn=(char *)(file_data_read(fi,binfile_cd_offset(cd)+sizeof(struct zip_lfh), lfh->zipfnln));
921         strncpy(buffer, zipfn, lfh->zipfnln);
922         buffer[lfh->zipfnln]='\0';
923         t->start=(int *)binfile_read_content(m, fi, binfile_cd_offset(cd), lfh);
924         t->end=t->start+lfh->zipuncmp/4;
925         t->fi=fi;
926         dbg(1,"0x%x '%s' %d %d,%d\n", lfh->ziplocsig, buffer, sizeof(*cd)+cd->zipcfnl, lfh->zipsize, lfh->zipuncmp);
927         file_data_free(fi, (unsigned char *)zipfn);
928         file_data_free(fi, (unsigned char *)lfh);
929         return t->start != NULL;
930 }
931
932
933 static int
934 map_binfile_handle_redirect(struct map_priv *m)
935 {
936         char *location=file_http_header(m->http, "location");
937         if (!location) {
938                 m->redirect=0;
939                 return 0;
940         }
941         if (m->redirect) 
942                 return 0;
943         m->redirect=1;
944         dbg(0,"redirected from %s to %s\n",m->url,location);
945         g_free(m->url);
946         m->url=g_strdup(location);
947         file_destroy(m->http);
948         m->http=NULL;
949
950         return 1;
951 }
952
953 static int
954 map_binfile_http_request(struct map_priv *m, struct attr **attrs)
955 {
956         if (!m->http) {
957                 m->http=file_create(NULL, attrs);
958         } else {
959                 file_request(m->http, attrs);
960         }
961         return 1;
962 }
963
964
965 static long long
966 map_binfile_download_size(struct map_priv *m)
967 {
968         struct attr url={attr_url};
969         struct attr http_method={attr_http_method};
970         struct attr persistent={attr_persistent};
971         struct attr *attrs[4];
972         int size_ret;
973         long long ret;
974         void *data;
975
976         do {
977                 attrs[0]=&url;
978                 url.u.str=m->url;
979                 attrs[1]=&http_method;
980                 http_method.u.str="HEAD";
981                 persistent.u.num=1;
982                 attrs[2]=&persistent;
983                 attrs[3]=NULL;
984
985                 map_binfile_http_request(m, attrs);
986                 data=file_data_read_special(m->http, 0, &size_ret);
987                 g_free(data);
988                 if (size_ret < 0) 
989                         return 0;
990         } while (map_binfile_handle_redirect(m));
991         
992         ret=file_size(m->http);
993         dbg(1,"file size "LONGLONG_FMT"\n",ret);
994         return ret;
995 }
996
997
998 static int
999 map_binfile_http_close(struct map_priv *m)
1000 {
1001         if (m->http) {
1002                 file_destroy(m->http);
1003                 m->http=NULL;
1004         }
1005         return 1;
1006 }
1007
1008
1009 static struct file *
1010 map_binfile_http_range(struct map_priv *m, long long offset, int size)
1011 {
1012         struct attr *attrs[4];
1013         struct attr url={attr_url};
1014         struct attr http_header={attr_http_header};
1015         struct attr persistent={attr_persistent};
1016
1017         persistent.u.num=1;     
1018         attrs[0]=&url;
1019         attrs[1]=&http_header;
1020         attrs[2]=&persistent;
1021         attrs[3]=NULL;
1022
1023         url.u.str=m->url;
1024         http_header.u.str=g_strdup_printf("Range: bytes="LONGLONG_FMT"-"LONGLONG_FMT,offset, offset+size-1);
1025         map_binfile_http_request(m, attrs);
1026         g_free(http_header.u.str);
1027         return m->http;
1028 }
1029
1030 static unsigned char *
1031 map_binfile_download_range(struct map_priv *m, long long offset, int size)
1032 {
1033         unsigned char *ret;
1034         int size_ret;
1035         struct file *http=map_binfile_http_range(m, offset, size);
1036
1037         ret=file_data_read_special(http, size, &size_ret);
1038         if (size_ret != size) {
1039                 dbg(0,"size %d vs %d\n",size,size_ret);
1040                 g_free(ret);
1041                 return NULL;
1042         }
1043         return ret;
1044 }
1045
1046 static struct zip_cd *
1047 download_cd(struct map_download *download)
1048 {
1049         struct map_priv *m=download->m;
1050         struct zip64_eoc *zip64_eoc=(struct zip64_eoc *)file_data_read(m->fi, 0, sizeof(*zip64_eoc));
1051         struct zip_cd *cd=(struct zip_cd *)map_binfile_download_range(m, zip64_eoc->zip64eofst+download->zipfile*m->cde_size,m->cde_size);
1052         file_data_free(m->fi, (unsigned char *)zip64_eoc);
1053         dbg(0,"needed cd, result %p\n",cd);
1054         return cd;
1055 }
1056
1057 static int
1058 download_request(struct map_download *download)
1059 {
1060         struct attr url={attr_url};
1061         struct attr http_header={attr_http_header};
1062         struct attr persistent={attr_persistent};
1063         struct attr *attrs[4];
1064
1065         if(!download->m->download_enabled)
1066         {
1067                 dbg(0,"Tried downloading while it's not allowed\n");
1068                 return 0;
1069         }
1070         attrs[0]=&url;
1071         persistent.u.num=1;
1072         attrs[1]=&persistent;
1073         attrs[2]=NULL;
1074         if (strchr(download->m->url,'?')) {
1075                 url.u.str=g_strdup_printf("%smemberid=%d",download->m->url,download->zipfile);
1076                 download->dl_size=-1;
1077         } else {
1078                 long long offset=binfile_cd_offset(download->cd_copy);
1079                 int size=download->cd_copy->zipcsiz+sizeof(struct zip_lfh)+download->cd_copy->zipcfnl;
1080                 url.u.str=g_strdup(download->m->url);
1081                 http_header.u.str=g_strdup_printf("Range: bytes="LONGLONG_FMT"-"LONGLONG_FMT,offset,offset+size-1);
1082                 attrs[2]=&http_header;
1083                 attrs[3]=NULL;
1084                 download->dl_size=size;
1085         }
1086         dbg(0,"encountered missing tile %d %s(%s), Downloading %d bytes at "LONGLONG_FMT"\n",download->zipfile, url.u.str,(char *)(download->cd_copy+1), download->dl_size, download->offset);
1087         map_binfile_http_request(download->m, attrs);
1088         g_free(url.u.str);
1089         download->http=download->m->http;
1090         return 1;
1091 }
1092
1093
1094 static int
1095 download_start(struct map_download *download)
1096 {
1097         long long offset;
1098         struct zip_eoc *eoc;
1099
1100         if (!download->cd->zipcensig) {
1101                 download->cd_copy=download_cd(download);
1102         } else {
1103                 download->cd_copy=g_malloc(download->m->cde_size);
1104                 memcpy(download->cd_copy, download->cd, download->m->cde_size);
1105         }
1106         file_data_remove(download->file, (unsigned char *)download->cd);
1107         download->cd=NULL;
1108         offset=file_size(download->file);
1109         offset-=sizeof(struct zip_eoc);
1110         eoc=(struct zip_eoc *)file_data_read(download->file, offset, sizeof(struct zip_eoc));
1111         download->zip_eoc=g_malloc(sizeof(struct zip_eoc));
1112         memcpy(download->zip_eoc, eoc, sizeof(struct zip_eoc));
1113         file_data_remove(download->file, (unsigned char *)eoc);
1114         download->start_offset=download->offset=offset;
1115         return download_request(download);
1116 }
1117
1118 static int
1119 download_download(struct map_download *download)
1120 {
1121         int size=64*1024,size_ret;
1122         unsigned char *data;
1123         if (download->dl_size != -1 && size > download->dl_size)
1124                 size=download->dl_size;
1125         if (!size)
1126                 return 1;
1127         data=file_data_read_special(download->http, size, &size_ret);
1128         if (!download->read && download->m->http && map_binfile_handle_redirect(download->m)) {
1129                 g_free(data);
1130                 download_request(download);
1131                 return 0;
1132         }
1133
1134         dbg(1,"got %d bytes writing at offset "LONGLONG_FMT"\n",size_ret,download->offset);
1135         if (size_ret <= 0) {
1136                 g_free(data);
1137                 return 1;
1138         }
1139         file_data_write(download->file, download->offset, size_ret, data);
1140         download->offset+=size_ret;
1141         download->read+=size_ret;
1142         download->dl_size-=size_ret;
1143         if (download->dl_size != -1)
1144                 download->progress=download->read*100/(download->read+download->dl_size);
1145         return 0;
1146 }
1147
1148 static int
1149 download_finish(struct map_download *download)
1150 {
1151         struct zip_lfh *lfh;
1152         char *lfh_filename;
1153         struct zip_cd_ext *ext;
1154         long long lfh_offset;
1155         file_data_write(download->file, download->offset, sizeof(struct zip_eoc), (void *)download->zip_eoc);
1156         lfh=(struct zip_lfh *)(file_data_read(download->file,download->start_offset, sizeof(struct zip_lfh)));
1157         ext=binfile_cd_ext(download->cd_copy);
1158         if (ext)
1159                 ext->zipofst=download->start_offset;
1160         else
1161                 download->cd_copy->zipofst=download->start_offset;
1162         download->cd_copy->zipcsiz=lfh->zipsize;
1163         download->cd_copy->zipcunc=lfh->zipuncmp;
1164         download->cd_copy->zipccrc=lfh->zipcrc;
1165         lfh_offset = binfile_cd_offset(download->cd_copy)+sizeof(struct zip_lfh);
1166         lfh_filename=(char *)file_data_read(download->file,lfh_offset,lfh->zipfnln);
1167         memcpy(download->cd_copy+1,lfh_filename,lfh->zipfnln);
1168         file_data_remove(download->file,(void *)lfh_filename);
1169         file_data_remove(download->file,(void *)lfh);
1170         file_data_write(download->file, download->m->eoc->zipeofst + download->zipfile*download->m->cde_size, binfile_cd_extra(download->cd_copy)+sizeof(struct zip_cd), (void *)download->cd_copy);
1171         file_data_flush(download->file, download->m->eoc->zipeofst + download->zipfile*download->m->cde_size, sizeof(struct zip_cd));
1172
1173         g_free(download->cd_copy);
1174         download->cd=(struct zip_cd *)(file_data_read(download->file, download->m->eoc->zipeofst + download->zipfile*download->m->cde_size, download->m->cde_size));
1175         cd_to_cpu(download->cd);
1176         dbg(1,"Offset %d\n",download->cd->zipofst);
1177         return 1;
1178 }
1179
1180 static int
1181 download_planet_size(struct map_download *download)
1182 {
1183         download->size=map_binfile_download_size(download->m);
1184         dbg(0,"Planet size "LONGLONG_FMT"\n",download->size);
1185         if (!download->size)
1186                 return 0;
1187         return 1;
1188 }
1189
1190 static int
1191 download_eoc(struct map_download *download)
1192 {
1193         download->zip64_eoc=(struct zip64_eoc *)map_binfile_download_range(download->m, download->size-98, 98);
1194         if (!download->zip64_eoc)
1195                 return 0;
1196         download->zip64_eocl=(struct zip64_eocl *)(download->zip64_eoc+1);
1197         download->zip_eoc=(struct zip_eoc *)(download->zip64_eocl+1);
1198         if (download->zip64_eoc->zip64esig != zip64_eoc_sig || download->zip64_eocl->zip64lsig != zip64_eocl_sig || download->zip_eoc->zipesig != zip_eoc_sig)
1199         {
1200                 dbg(0,"wrong signature on zip64_eoc downloaded from "LONGLONG_FMT"\n",download->size-98);
1201                 g_free(download->zip64_eoc);
1202                 return 0;
1203         }
1204         return 1;
1205 }
1206
1207 static int
1208 download_directory_start(struct map_download *download)
1209 {
1210         download->http=map_binfile_http_range(download->m, download->zip64_eoc->zip64eofst, download->zip64_eoc->zip64ecsz);
1211         if (!download->http)
1212                 return 0;
1213         return 1;
1214 }
1215
1216 static int
1217 download_directory_do(struct map_download *download)
1218 {
1219         int count;
1220
1221         for (count = 0 ; count < 100 ; count++) {
1222                 int cd_xlen, size_ret;
1223                 unsigned char *cd_data;
1224                 struct zip_cd *cd;
1225                 cd=(struct zip_cd *)file_data_read_special(download->http, sizeof(*cd), &size_ret);
1226                 cd->zipcunc=0;
1227                 dbg(1,"size_ret=%d\n",size_ret);
1228                 if (!size_ret)
1229                         return 0;
1230                 if (size_ret != sizeof(*cd) || cd->zipcensig != zip_cd_sig) {
1231                         dbg(0,"error1 size=%d vs %d\n",size_ret, sizeof(*cd));
1232                         return 0;
1233                 }
1234                 file_data_write(download->file, download->offset, sizeof(*cd), (unsigned char *)cd);
1235                 download->offset+=sizeof(*cd);
1236                 cd_xlen=cd->zipcfnl+cd->zipcxtl;
1237                 cd_data=file_data_read_special(download->http, cd_xlen, &size_ret);
1238                 if (size_ret != cd_xlen) {
1239                         dbg(0,"error2 size=%d vs %d\n",size_ret,cd_xlen);
1240                         return 0;
1241                 }
1242                 file_data_write(download->file, download->offset, cd_xlen, cd_data);
1243                 download->offset+=cd_xlen;
1244                 g_free(cd);
1245                 g_free(cd_data);
1246         }
1247         return 1;
1248 }
1249
1250 static int
1251 download_directory_finish(struct map_download *download)
1252 {
1253         download->http=NULL;
1254         return 1;
1255 }
1256
1257 static int
1258 download_initial_finish(struct map_download *download)
1259 {
1260         download->zip64_eoc->zip64eofst=download->cd1offset;
1261         download->zip64_eocl->zip64lofst=download->offset;
1262         download->zip_eoc->zipeofst=download->cd1offset;
1263 #if 0
1264         file_data_write(download->file, download->offset, sizeof(*download->zip64_eoc), (unsigned char *)download->zip64_eoc);
1265         download->offset+=sizeof(*download->zip64_eoc);
1266         file_data_write(download->file, download->offset, sizeof(*download->zip64_eocl), (unsigned char *)download->zip64_eocl);
1267         download->offset+=sizeof(*download->zip64_eocl);
1268 #endif
1269         file_data_write(download->file, download->offset, sizeof(*download->zip_eoc), (unsigned char *)download->zip_eoc);
1270         download->offset+=sizeof(*download->zip_eoc);
1271         g_free(download->zip64_eoc);
1272         download->zip64_eoc=NULL;
1273         return 1;
1274 }
1275
1276 static void
1277 push_zipfile_tile_do(struct map_rect_priv *mr, struct zip_cd *cd, int zipfile, int offset, int length)
1278
1279 {
1280         struct tile t;
1281         struct map_priv *m=mr->m;
1282         struct file *f=m->fi;
1283
1284         dbg(1,"enter %p %d\n", mr, zipfile);
1285 #ifdef DEBUG_SIZE
1286 #if DEBUG_SIZE > 0
1287         {
1288                 char filename[cd->zipcfnl+1];
1289                 memcpy(filename, cd+1, cd->zipcfnl);
1290                 filename[cd->zipcfnl]='\0';
1291                 dbg(0,"enter %d (%s) %d\n",zipfile, filename, cd->zipcunc);
1292         }
1293 #endif
1294         mr->size+=cd->zipcunc;
1295 #endif
1296         t.zipfile_num=zipfile;
1297         if (zipfile_to_tile(m, cd, &t)) 
1298                 push_tile(mr, &t, offset, length);
1299         file_data_free(f, (unsigned char *)cd);
1300 }
1301
1302
1303 static struct zip_cd *
1304 download(struct map_priv *m, struct map_rect_priv *mr, struct zip_cd *cd, int zipfile, int offset, int length, int async)
1305 {
1306         struct map_download *download;
1307
1308         if(!m->download_enabled)
1309                 return NULL;
1310
1311         if (async == 2) {
1312                 download=m->download;
1313         } else {
1314                 download=g_new0(struct map_download, 1);
1315                 if (mr) {
1316                         download->m=m;
1317                         download->mr=mr;
1318                         download->file=m->fi;
1319                         download->cd=cd;
1320                         download->zipfile=zipfile;
1321                         download->toffset=offset;
1322                         download->tlength=length;
1323                         download->state=1;
1324                 } else {
1325                         struct attr readwrite={attr_readwrite,{(void *)1}};
1326                         struct attr create={attr_create,{(void *)1}};
1327                         struct attr *attrs[3];
1328                         attrs[0]=&readwrite;
1329                         attrs[1]=&create;
1330                         attrs[2]=NULL;
1331                         download->file=file_create(m->filename,attrs);
1332                         download->m=m;
1333                         download->state=4;
1334                 }
1335         }
1336         if (async == 1) {
1337                 m->download=download;
1338                 g_free(m->progress);
1339                 if (download->mr) 
1340                         m->progress=g_strdup_printf("Download Tile %d 0%%",download->zipfile);
1341                 else
1342                         m->progress=g_strdup_printf("Download Map Information 0%%");
1343                 callback_list_call_attr_0(m->cbl, attr_progress);
1344                 return NULL;
1345         }
1346         for (;;) {
1347                 dbg(0,"state=%d\n",download->state);
1348                 switch (download->state) {
1349                 case 0:
1350                         dbg(0,"error\n");
1351                         break;
1352                 case 1:
1353                         if (download_start(download))
1354                                 download->state=2;
1355                         else
1356                                 download->state=0;
1357                         break;
1358                 case 2:
1359                         if (download_download(download)) 
1360                                 download->state=3;
1361                         else {
1362                                 g_free(m->progress);
1363                                 m->progress=g_strdup_printf("Download Tile %d %d%%",download->zipfile,download->progress);
1364                                 callback_list_call_attr_0(m->cbl, attr_progress);
1365                         }
1366                         break;
1367                 case 3:
1368                         if (download_finish(download)) {
1369                                 struct zip_cd *ret;
1370                                 g_free(m->progress);
1371                                 m->progress=g_strdup_printf("Download Tile %d 100%%",download->zipfile);
1372                                 callback_list_call_attr_0(m->cbl, attr_progress);
1373                                 if (async) {
1374                                         push_zipfile_tile_do(download->mr, download->cd, download->zipfile, download->toffset, download->tlength);
1375                                         ret=NULL;
1376                                 } else
1377                                         ret=download->cd;
1378                                 g_free(m->progress);
1379                                 m->progress=NULL;
1380                                 g_free(download);
1381                                 if (async)
1382                                         m->download=NULL;
1383                                 return ret;
1384                         } else
1385                                 download->state=0;
1386                         break;
1387                 case 4:
1388                         if (download_planet_size(download))
1389                                 download->state=5;
1390                         else
1391                                 download->state=0;
1392                         break;
1393                 case 5:
1394                         g_free(m->progress);
1395                         m->progress=g_strdup_printf("Download Map Information 50%%");
1396                         callback_list_call_attr_0(m->cbl, attr_progress);
1397                         if (download_eoc(download))
1398                                 download->state=6;
1399                         else {
1400                                 dbg(0,"download of eoc failed\n");
1401                                 download->state=0;
1402                         }
1403                         break;
1404                 case 6:
1405                         g_free(m->progress);
1406                         m->progress=g_strdup_printf("Download Map Information 100%%");
1407                         callback_list_call_attr_0(m->cbl, attr_progress);
1408                         if (download_directory_start(download))
1409                                 download->state=7;
1410                         else
1411                                 download->state=0;
1412                         break;
1413                 case 7:
1414                         g_free(m->progress);
1415                         m->progress=g_strdup_printf("Download Map Directory %d%%",(int)(download->offset*100/download->zip64_eoc->zip64ecsz));
1416                         callback_list_call_attr_0(m->cbl, attr_progress);
1417                         if (!download_directory_do(download))
1418                                 download->state=8;
1419                         break;
1420                 case 8:
1421                         if (download_directory_finish(download))
1422                                 download->state=9;
1423                         else
1424                                 download->state=0;
1425                         break;
1426                 case 9:
1427                         download_initial_finish(download);
1428                         m->fi=download->file;
1429                         g_free(m->progress);
1430                         m->progress=NULL;
1431                         g_free(download);
1432                         if (async)
1433                                 m->download=NULL;
1434                         map_binfile_open(m);
1435                         break;
1436                 }
1437                 if (async)
1438                         return NULL;
1439         }
1440 }
1441
1442 static int
1443 push_zipfile_tile(struct map_rect_priv *mr, int zipfile, int offset, int length, int async)
1444 {
1445         struct map_priv *m=mr->m;
1446         struct file *f=m->fi;
1447         long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst;
1448         struct zip_cd *cd=(struct zip_cd *)(file_data_read(f, cdoffset + zipfile*m->cde_size, m->cde_size));
1449         dbg(1,"read from "LONGLONG_FMT" %d bytes\n",cdoffset + zipfile*m->cde_size, m->cde_size);
1450         cd_to_cpu(cd);
1451         if (!cd->zipcunc && m->url) {
1452                 cd=download(m, mr, cd, zipfile, offset, length, async);
1453                 if (!cd)
1454                         return 1;
1455         }
1456         push_zipfile_tile_do(mr, cd, zipfile, offset, length);
1457         return 0;
1458 }
1459
1460 static struct map_rect_priv *
1461 map_rect_new_binfile_int(struct map_priv *map, struct map_selection *sel)
1462 {
1463         struct map_rect_priv *mr;
1464
1465         binfile_check_version(map);
1466         dbg(1,"map_rect_new_binfile\n");
1467         if (!map->fi && !map->url)
1468                 return NULL;
1469         map_binfile_http_close(map);
1470         mr=g_new0(struct map_rect_priv, 1);
1471         mr->m=map;
1472         mr->sel=sel;
1473         mr->item.id_hi=0;
1474         mr->item.id_lo=0;
1475         mr->item.meth=&methods_binfile;
1476         mr->item.priv_data=mr;
1477         return mr;
1478 }
1479
1480 static void
1481 tile_bbox(char *tile, int len, struct coord_rect *r)
1482 {
1483         struct coord c;
1484         int overlap=1;
1485         int xo,yo;
1486         struct coord_rect world_bbox = {
1487                 { -20000000,  20000000}, /* lu */
1488                 {  20000000, -20000000}, /* rl */
1489         };
1490         *r=world_bbox;
1491         while (len) {
1492                 c.x=(r->lu.x+r->rl.x)/2;
1493                 c.y=(r->lu.y+r->rl.y)/2;
1494                 xo=(r->rl.x-r->lu.x)*overlap/100;
1495                 yo=(r->lu.y-r->rl.y)*overlap/100;
1496                 switch (*tile) {
1497                 case 'a':
1498                         r->lu.x=c.x-xo;
1499                         r->rl.y=c.y-yo;
1500                         break;
1501                 case 'b':
1502                         r->rl.x=c.x+xo;
1503                         r->rl.y=c.y-yo;
1504                         break;
1505                 case 'c':
1506                         r->lu.x=c.x-xo;
1507                         r->lu.y=c.y+yo;
1508                         break;
1509                 case 'd':
1510                         r->rl.x=c.x+xo;
1511                         r->lu.y=c.y+yo;
1512                         break;
1513                 default:
1514                         return;
1515                 }
1516                 tile++;
1517                 len--;
1518         }
1519 }
1520
1521 static int
1522 map_download_selection_check(struct zip_cd *cd, struct map_selection *sel)
1523 {
1524         struct coord_rect cd_rect;
1525         if (cd->zipcunc)
1526                 return 0;
1527         tile_bbox((char *)(cd+1), cd->zipcfnl, &cd_rect);
1528         while (sel) {
1529                 if (coord_rect_overlap(&cd_rect, &sel->u.c_rect))
1530                         return 1;
1531                 sel=sel->next;
1532         }
1533         return 0;
1534 }
1535
1536 static void
1537 map_download_selection(struct map_priv *m, struct map_rect_priv *mr, struct map_selection *sel)
1538 {
1539         int i;
1540         struct zip_cd *cd;
1541         for (i = 0 ; i < m->zip_members ; i++) {
1542                 cd=binfile_read_cd(m, m->cde_size*i, -1);
1543                 if (map_download_selection_check(cd, sel)) 
1544                         download(m, mr, cd, i, 0, 0, 0);
1545                 file_data_free(m->fi, (unsigned char *)cd);
1546         }
1547 }
1548
1549 static struct map_rect_priv *
1550 map_rect_new_binfile(struct map_priv *map, struct map_selection *sel)
1551 {
1552         struct map_rect_priv *mr=map_rect_new_binfile_int(map, sel);
1553         struct tile t;
1554         dbg(1,"zip_members=%d\n", map->zip_members);
1555         if (map->url && map->fi && sel && sel->order == 255) {
1556                 map_download_selection(map, mr, sel);
1557         }
1558         if (map->eoc)
1559                 mr->status=1;
1560         else {
1561                 unsigned char *d;
1562                 if (map->fi) {
1563                         d=file_data_read(map->fi, 0, map->fi->size);
1564                         t.start=(int *)d;
1565                         t.end=(int *)(d+map->fi->size);
1566                         t.fi=map->fi;
1567                         t.zipfile_num=0;
1568                         t.mode=0;
1569                         push_tile(mr, &t, 0, 0);
1570                 } else if (map->url && !map->download) {
1571                         download(map, NULL, NULL, 0, 0, 0, 1);
1572                         mr->status=1;
1573                 }
1574         }
1575         return mr;
1576 }
1577
1578 static void
1579 write_changes_do(gpointer key, gpointer value, gpointer user_data)
1580 {
1581         struct binfile_hash_entry *entry=key;
1582         FILE *out=user_data;
1583         if (entry->flags) {
1584                 entry->flags=0;
1585                 fwrite(entry, sizeof(*entry)+(le32_to_cpu(entry->data[0])+1)*4, 1, out);
1586                 dbg(0,"yes\n");
1587         }
1588 }
1589
1590 static void
1591 write_changes(struct map_priv *m)
1592 {
1593         FILE *changes;
1594         char *changes_file;
1595         if (!m->changes)
1596                 return;
1597         changes_file=g_strdup_printf("%s.log",m->filename);
1598         changes=fopen(changes_file,"ab");
1599         g_hash_table_foreach(m->changes, write_changes_do, changes);
1600         fclose(changes);
1601         g_free(changes_file);
1602 }
1603
1604 static void
1605 load_changes(struct map_priv *m)
1606 {
1607         FILE *changes;
1608         char *changes_file;
1609         struct binfile_hash_entry entry,*e;
1610         int size;
1611         changes_file=g_strdup_printf("%s.log",m->filename);
1612         changes=fopen(changes_file,"rb");
1613         if (! changes) {
1614                 g_free(changes_file);
1615                 return;
1616         }
1617         m->changes=g_hash_table_new_full(binfile_hash_entry_hash, binfile_hash_entry_equal, g_free, NULL);
1618         while (fread(&entry, sizeof(entry), 1, changes) == 1) {
1619                 if (fread(&size, sizeof(size), 1, changes) != 1)
1620                         break;
1621                 e=g_malloc(sizeof(struct binfile_hash_entry)+(le32_to_cpu(size)+1)*4);
1622                 *e=entry;
1623                 e->data[0]=size;
1624                 if (fread(e->data+1, le32_to_cpu(size)*4, 1, changes) != 1)
1625                         break;
1626                 g_hash_table_replace(m->changes, e, e);
1627         }
1628         fclose(changes);
1629         g_free(changes_file);
1630 }
1631
1632
1633 static void
1634 map_rect_destroy_binfile(struct map_rect_priv *mr)
1635 {
1636         write_changes(mr->m);
1637         while (pop_tile(mr));
1638 #ifdef DEBUG_SIZE
1639         dbg(0,"size=%d kb\n",mr->size/1024);
1640 #endif
1641         if (mr->tiles[0].fi && mr->tiles[0].start)
1642                 file_data_free(mr->tiles[0].fi, (unsigned char *)(mr->tiles[0].start));
1643         g_free(mr->url);
1644         map_binfile_http_close(mr->m);
1645         g_free(mr);
1646 }
1647
1648 static void
1649 setup_pos(struct map_rect_priv *mr)
1650 {
1651         int size,coord_size;
1652         struct tile *t=mr->t;
1653         size=le32_to_cpu(t->pos[0]);
1654         if (size > 1024*1024 || size < 0) {
1655                 dbg(0,"size=0x%x\n", size);
1656 #if 0
1657                 fprintf(stderr,"offset=%d\n", (unsigned char *)(mr->pos)-mr->m->f->begin);
1658 #endif
1659                 dbg(0,"size error");
1660         }
1661         t->pos_next=t->pos+size+1;
1662         mr->item.type=le32_to_cpu(t->pos[1]);
1663         coord_size=le32_to_cpu(t->pos[2]);
1664         t->pos_coord_start=t->pos+3;
1665         t->pos_attr_start=t->pos_coord_start+coord_size;
1666 }
1667
1668 static int
1669 selection_contains(struct map_selection *sel, struct coord_rect *r, struct range *mima)
1670 {
1671         int order;
1672         if (! sel)
1673                 return 1;
1674         while (sel) {
1675                 if (coord_rect_overlap(r, &sel->u.c_rect)) {
1676                         order=sel->order;
1677                         dbg(1,"min %d max %d order %d\n", mima->min, mima->max, order);
1678                         if (!mima->min && !mima->max)
1679                                 return 1;
1680                         if (order >= mima->min && order <= mima->max)
1681                                 return 1;
1682                 }
1683                 sel=sel->next;
1684         }
1685         return 0;
1686 }
1687
1688 static void
1689 map_parse_country_binfile(struct map_rect_priv *mr)
1690 {
1691         struct attr at;
1692         if (binfile_attr_get(mr->item.priv_data, attr_country_id, &at)) {
1693                 if (at.u.num == mr->country_id)
1694                 {
1695                         if (binfile_attr_get(mr->item.priv_data, attr_zipfile_ref, &at))
1696                         {
1697                                 push_zipfile_tile(mr, at.u.num, 0, 0, 0);
1698                         }
1699                 }
1700         }
1701 }
1702
1703 static int
1704 map_parse_submap(struct map_rect_priv *mr, int async)
1705 {
1706         struct coord_rect r;
1707         struct coord c[2];
1708         struct attr at;
1709         struct range mima;
1710         if (binfile_coord_get(mr->item.priv_data, c, 2) != 2)
1711                 return 0;
1712         r.lu.x=c[0].x;
1713         r.lu.y=c[1].y;
1714         r.rl.x=c[1].x;
1715         r.rl.y=c[0].y;
1716         if (!binfile_attr_get(mr->item.priv_data, attr_order, &at))
1717                 return 0;
1718 #if __BYTE_ORDER == __BIG_ENDIAN
1719         mima.min=le16_to_cpu(at.u.range.max);
1720         mima.max=le16_to_cpu(at.u.range.min);
1721 #else
1722         mima=at.u.range;
1723 #endif
1724         if (!mr->m->eoc || !selection_contains(mr->sel, &r, &mima))
1725                 return 0;
1726         if (!binfile_attr_get(mr->item.priv_data, attr_zipfile_ref, &at))
1727                 return 0;
1728         dbg(1,"pushing zipfile %d from %d\n", at.u.num, mr->t->zipfile_num);
1729         return push_zipfile_tile(mr, at.u.num, 0, 0, async);
1730 }
1731
1732 static int
1733 push_modified_item(struct map_rect_priv *mr)
1734 {
1735         struct item_id id;
1736         struct binfile_hash_entry *entry;
1737         id.id_hi=mr->item.id_hi;
1738         id.id_lo=mr->item.id_lo;
1739         entry=g_hash_table_lookup(mr->m->changes, &id);
1740         if (entry) {
1741                 struct tile tn;
1742                 tn.pos_next=tn.pos=tn.start=entry->data;
1743                 tn.zipfile_num=mr->item.id_hi;
1744                 tn.mode=2;
1745                 tn.end=tn.start+le32_to_cpu(entry->data[0])+1;
1746                 push_tile(mr, &tn, 0, 0);
1747                 return 1;
1748         }
1749         return 0;
1750 }
1751
1752 static struct item *
1753 map_rect_get_item_binfile(struct map_rect_priv *mr)
1754 {
1755         struct tile *t;
1756         struct map_priv *m=mr->m;
1757         if (m->download) {
1758                 download(m, NULL, NULL, 0, 0, 0, 2);
1759                 return &busy_item;
1760         }
1761         if (mr->status == 1) {
1762                 mr->status=0;
1763                 if (push_zipfile_tile(mr, m->zip_members-1, 0, 0, 1))
1764                         return &busy_item;
1765         }
1766         for (;;) {
1767                 t=mr->t;
1768                 if (! t)
1769                         return NULL;
1770                 t->pos=t->pos_next;
1771                 if (t->pos >= t->end) {
1772                         if (pop_tile(mr))
1773                                 continue;
1774                         return NULL;
1775                 }
1776                 setup_pos(mr);
1777                 binfile_coord_rewind(mr);
1778                 binfile_attr_rewind(mr);
1779                 if ((mr->item.type == type_submap) && (!mr->country_id)) {
1780                         if (map_parse_submap(mr, 1))
1781                                 return &busy_item;
1782                         continue;
1783                 }
1784                 if (t->mode != 2) {
1785                         mr->item.id_hi=t->zipfile_num;
1786                         mr->item.id_lo=t->pos-t->start;
1787                         if (mr->m->changes && push_modified_item(mr))
1788                                 continue;
1789                 }
1790                 if (mr->country_id)
1791                 {
1792                         if (mr->item.type == type_countryindex) {
1793                                 map_parse_country_binfile(mr);
1794                         }
1795                         if (item_is_town(mr->item))
1796                         {
1797                                 return &mr->item;
1798                         } else {
1799                                 continue;
1800                         }
1801                 }
1802                 return &mr->item;
1803         }
1804 }
1805
1806 static struct item *
1807 map_rect_get_item_byid_binfile(struct map_rect_priv *mr, int id_hi, int id_lo)
1808 {
1809         struct tile *t;
1810         if (mr->m->eoc) {
1811                 while (pop_tile(mr));
1812                 push_zipfile_tile(mr, id_hi, 0, 0, 0);
1813         }
1814         t=mr->t;
1815         t->pos=t->start+id_lo;
1816         mr->item.id_hi=id_hi;
1817         mr->item.id_lo=id_lo;
1818         if (mr->m->changes)
1819                 push_modified_item(mr);
1820         setup_pos(mr);
1821         binfile_coord_rewind(mr);
1822         binfile_attr_rewind(mr);
1823         return &mr->item;
1824 }
1825
1826 static int
1827 binmap_search_by_index(struct map_priv *map, struct item *item, struct map_rect_priv **ret)
1828 {
1829         struct attr zipfile_ref;
1830         int *data;
1831
1832         if (!item) {
1833                 *ret=NULL;
1834                 return 0;
1835         }
1836         if (item_attr_get(item, attr_item_id, &zipfile_ref)) {
1837                 data=zipfile_ref.u.data;
1838                 *ret=map_rect_new_binfile_int(map, NULL);
1839                 push_zipfile_tile(*ret, le32_to_cpu(data[0]), le32_to_cpu(data[1]), -1, 0);
1840                 return 3;
1841         }
1842         if (item_attr_get(item, attr_zipfile_ref, &zipfile_ref)) {
1843                 *ret=map_rect_new_binfile_int(map, NULL);
1844                 push_zipfile_tile(*ret, zipfile_ref.u.num, 0, 0, 0);
1845                 return 1;
1846         }
1847         if (item_attr_get(item, attr_zipfile_ref_block, &zipfile_ref)) {
1848                 data=zipfile_ref.u.data;
1849                 *ret=map_rect_new_binfile_int(map, NULL);
1850                 push_zipfile_tile(*ret, le32_to_cpu(data[0]), le32_to_cpu(data[1]), le32_to_cpu(data[2]), 0);
1851                 return 2;
1852         }
1853         *ret=NULL;
1854         return 0;
1855 }
1856
1857 static struct map_rect_priv *
1858 binmap_search_street_by_place(struct map_priv *map, struct item *town, struct coord *c, struct map_selection *sel)
1859 {
1860         struct attr town_name, poly_town_name;
1861         struct map_rect_priv *map_rec2;
1862         struct item *place;
1863         int found=0;
1864
1865         if (!item_attr_get(town, attr_label, &town_name))
1866                 return NULL;
1867         sel->range = item_range_all;
1868         sel->order = 18;
1869         sel->next = NULL;
1870         sel->u.c_rect.lu=*c;
1871         sel->u.c_rect.rl=*c;
1872         map_rec2=map_rect_new_binfile(map, sel);
1873         while ((place=map_rect_get_item_binfile(map_rec2))) {
1874                 if (item_is_poly_place(*place) &&
1875                     item_attr_get(place, attr_label, &poly_town_name) && 
1876                     !strcmp(poly_town_name.u.str,town_name.u.str)) {
1877                                 struct coord c[128];
1878                                 int i,count;
1879                                 found=1;
1880                                 while ((count=item_coord_get(place, c, 128))) {
1881                                         for (i = 0 ; i < count ; i++)
1882                                                 coord_rect_extend(&sel->u.c_rect, &c[i]);
1883                                 }
1884                 }
1885         }
1886         map_rect_destroy_binfile(map_rec2);
1887         if (found)
1888                 return map_rect_new_binfile(map, sel);
1889         return NULL;
1890 }
1891
1892 static struct map_rect_priv *
1893 binmap_search_street_by_estimate(struct map_priv *map, struct item *town, struct coord *c, struct map_selection *sel)
1894 {
1895         int size = 10000;
1896         switch (town->type) {
1897                 case type_town_label_1e7:
1898                 case type_town_label_5e6:
1899                 case type_town_label_2e6:
1900                 case type_town_label_1e6:
1901                 case type_town_label_5e5:
1902                 case type_town_label_2e5:
1903                 case type_district_label_1e7:
1904                 case type_district_label_5e6:
1905                 case type_district_label_2e6:
1906                 case type_district_label_1e6:
1907                 case type_district_label_5e5:
1908                 case type_district_label_2e5:
1909                         size = 10000;
1910                         break;
1911                 case type_town_label_1e5:
1912                 case type_town_label_5e4:
1913                 case type_town_label_2e4:
1914                 case type_district_label_1e5:
1915                 case type_district_label_5e4:
1916                 case type_district_label_2e4:
1917                         size = 5000;
1918                         break;
1919                 case type_town_label_1e4:
1920                 case type_town_label_5e3:
1921                 case type_town_label_2e3:
1922                 case type_district_label_1e4:
1923                 case type_district_label_5e3:
1924                 case type_district_label_2e3:
1925                         size = 2500;
1926                         break;
1927                 case type_town_label_1e3:
1928                 case type_town_label_5e2:
1929                 case type_town_label_2e2:
1930                 case type_town_label_1e2:
1931                 case type_town_label_5e1:
1932                 case type_town_label_2e1:
1933                 case type_town_label_1e1:
1934                 case type_town_label_5e0:
1935                 case type_town_label_2e0:
1936                 case type_town_label_1e0:
1937                 case type_town_label_0e0:
1938                 case type_district_label_1e3:
1939                 case type_district_label_5e2:
1940                 case type_district_label_2e2:
1941                 case type_district_label_1e2:
1942                 case type_district_label_5e1:
1943                 case type_district_label_2e1:
1944                 case type_district_label_1e1:
1945                 case type_district_label_5e0:
1946                 case type_district_label_2e0:
1947                 case type_district_label_1e0:
1948                 case type_district_label_0e0:
1949                         size = 1000;
1950                         break;
1951                 default:
1952                         break;
1953         }
1954         sel->u.c_rect.lu.x = c->x-size;
1955         sel->u.c_rect.lu.y = c->y+size;
1956         sel->u.c_rect.rl.x = c->x+size;
1957         sel->u.c_rect.rl.y = c->y-size;
1958         return map_rect_new_binfile(map, sel);
1959 }
1960
1961 static struct map_rect_priv *
1962 binmap_search_housenumber_by_estimate(struct map_priv *map, struct coord *c, struct map_selection *sel)
1963 {
1964         int size = 20;
1965         sel->u.c_rect.lu.x = c->x-size;
1966         sel->u.c_rect.lu.y = c->y+size;
1967         sel->u.c_rect.rl.x = c->x+size;
1968         sel->u.c_rect.rl.y = c->y-size;
1969
1970         sel->range = item_range_all;
1971         sel->order = 18;
1972         //sel->next = NULL;
1973
1974         return map_rect_new_binfile(map, sel);
1975 }
1976
1977 static struct map_search_priv *
1978 binmap_search_new(struct map_priv *map, struct item *item, struct attr *search, int partial)
1979 {
1980         struct map_rect_priv *map_rec;
1981         struct map_search_priv *msp=g_new0(struct map_search_priv, 1);
1982         struct item *town;
1983         
1984         msp->search = search;
1985         msp->partial = partial;
1986         /*
1987      * NOTE: If you implement search for other attributes than attr_town_name and attr_street_name,
1988      * please update this comment and the documentation for map_search_new() in map.c
1989      */
1990         switch (search->type) {
1991                 case attr_country_name:
1992                         break;
1993                 case attr_town_name:
1994                 case attr_town_or_district_name:
1995                         map_rec = map_rect_new_binfile(map, NULL);
1996                         if (!map_rec) 
1997                                 break;
1998                         map_rec->country_id = item->id_lo;
1999                         msp->mr = map_rec;
2000                         return msp;
2001                         break;
2002                 case attr_town_postal:
2003                         break;
2004                 case attr_street_name:
2005                         if (! item->map)
2006                                 break;
2007                         if (!map_priv_is(item->map, map))
2008                                 break;
2009                         map_rec = map_rect_new_binfile(map, NULL);
2010                         town = map_rect_get_item_byid_binfile(map_rec, item->id_hi, item->id_lo);
2011                         if (town) {
2012                                 struct coord c;
2013
2014                                 if (binmap_search_by_index(map, town, &msp->mr))
2015                                         msp->mode = 1;
2016                                 else {
2017                                         if (item_coord_get(town, &c, 1)) {
2018                                                 if ((msp->mr=binmap_search_street_by_place(map, town, &c, &msp->ms))) 
2019                                                         msp->mode = 2;
2020                                                 else {
2021                                                         msp->mr=binmap_search_street_by_estimate(map, town, &c, &msp->ms);
2022                                                         msp->mode = 3;
2023                                                 }       
2024                                         }
2025                                 }
2026                                 map_rect_destroy_binfile(map_rec);
2027                                 if (!msp->mr)
2028                                         break;
2029                                 return msp;
2030                         }
2031                         map_rect_destroy_binfile(map_rec);
2032                         break;
2033                 case attr_house_number:
2034                         dbg(1,"case house_number");
2035                         if (! item->map)
2036                                 break;
2037                         if (!map_priv_is(item->map, map))
2038                                 break;
2039                         msp->map=map;
2040                         msp->mr_item = map_rect_new_binfile(map, NULL);
2041                         msp->item = map_rect_get_item_byid_binfile(msp->mr_item, item->id_hi, item->id_lo);
2042                         if (binmap_search_by_index(map, msp->item, &msp->mr) != 3) {
2043                                 struct coord c;
2044                                 if (item_coord_get(msp->item, &c, 1))
2045                                 {
2046                                         msp->mr=binmap_search_housenumber_by_estimate(map, &c, &msp->ms);
2047                                         msp->mode = 2;
2048                                 }
2049                                 map_rect_destroy_binfile(msp->mr_item);
2050                                 msp->mr_item=NULL;
2051                         }
2052                         if (!msp->mr)
2053                         {
2054                                 break;
2055                         }
2056                         return msp;
2057                 default:
2058                         break;
2059         }
2060         g_free(msp);
2061         return NULL;
2062 }
2063
2064 static int
2065 ascii_cmp(char *name, char *match, int partial)
2066 {
2067         if (partial)
2068                 return g_ascii_strncasecmp(name, match, strlen(match));
2069         else
2070                 return g_ascii_strcasecmp(name, match);
2071 }
2072
2073 struct duplicate
2074 {
2075         struct coord c;
2076         char str[0];
2077 };
2078
2079 static guint
2080 duplicate_hash(gconstpointer key)
2081 {
2082         const struct duplicate *d=key;
2083         return d->c.x^d->c.y^g_str_hash(d->str);
2084 }
2085
2086 static gboolean
2087 duplicate_equal(gconstpointer a, gconstpointer b)
2088 {
2089         const struct duplicate *da=a;
2090         const struct duplicate *db=b;
2091         return (da->c.x == db->c.x && da->c.y == da->c.y && g_str_equal(da->str,db->str));
2092 }
2093
2094 /**
2095  * @brief
2096  * @param msp pointer to private map search data
2097  * @param item item to check
2098  * @param attr_type
2099  */
2100 static int
2101 duplicate(struct map_search_priv *msp, struct item *item, enum attr_type attr_type)
2102 {
2103         struct attr attr;
2104         if (!msp->search_results)
2105                 msp->search_results = g_hash_table_new_full(duplicate_hash, duplicate_equal, g_free, NULL);
2106         binfile_attr_rewind(item->priv_data);
2107         if (!item_attr_get(item, attr_type, &attr))
2108                 return 1;
2109         {
2110                 int len=sizeof(struct  coord)+strlen(attr.u.str)+1;
2111                 char *buffer=g_alloca(sizeof(char)*len);
2112                 struct duplicate *d=(struct duplicate *)buffer;
2113                 if (!item_coord_get(item, &d->c, 1)) {
2114                         d->c.x=0;
2115                         d->c.y=0;
2116                 }
2117                 binfile_coord_rewind(item->priv_data);
2118                 strcpy(d->str, attr.u.str);
2119                 if (!g_hash_table_lookup(msp->search_results, d)) {
2120                         struct duplicate *dc=g_malloc(len);
2121                         memcpy(dc, d, len);
2122                         g_hash_table_insert(msp->search_results, dc, GINT_TO_POINTER(1));
2123                         binfile_attr_rewind(item->priv_data);
2124                         return 0;
2125                 }
2126         }
2127         return 2;
2128 }
2129
2130 static struct item *
2131 binmap_search_get_item(struct map_search_priv *map_search)
2132 {
2133         struct item* it;
2134         struct attr at;
2135
2136         for (;;) {
2137                 while ((it  = map_rect_get_item_binfile(map_search->mr))) {
2138                         switch (map_search->search->type) {
2139                         case attr_town_name:
2140                         case attr_district_name:
2141                         case attr_town_or_district_name:
2142                                 if (map_search->mr->tile_depth > 1 && item_is_town(*it) && map_search->search->type != attr_district_name) {
2143                                         if (binfile_attr_get(it->priv_data, attr_town_name_match, &at) || binfile_attr_get(it->priv_data, attr_town_name, &at)) {
2144                                                 if (!ascii_cmp(at.u.str, map_search->search->u.str, map_search->partial) && !duplicate(map_search, it, attr_town_name)) 
2145                                                         return it;
2146                                         }
2147                                 }
2148                                 if (map_search->mr->tile_depth > 1 && item_is_district(*it) && map_search->search->type != attr_town_name) {
2149                                         if (binfile_attr_get(it->priv_data, attr_district_name_match, &at) || binfile_attr_get(it->priv_data, attr_district_name, &at)) {
2150                                                 if (!ascii_cmp(at.u.str, map_search->search->u.str, map_search->partial) && !duplicate(map_search, it, attr_town_name)) 
2151                                                         return it;
2152                                         }
2153                                 }
2154                                 break;
2155                         case attr_street_name:
2156                                 if (map_search->mode == 1) {
2157                                         if (binfile_attr_get(it->priv_data, attr_street_name_match, &at) || binfile_attr_get(it->priv_data, attr_street_name, &at)) {
2158                                                 if (!ascii_cmp(at.u.str, map_search->search->u.str, map_search->partial) && !duplicate(map_search, it, attr_street_name)) {
2159                                                         return it;
2160                                                 }
2161                                         }
2162                                         continue;
2163                                 }
2164                                 if (item_is_street(*it)) {
2165                                         struct attr at;
2166                                         if (map_selection_contains_item_rect(map_search->mr->sel, it) && binfile_attr_get(it->priv_data, attr_label, &at)) {
2167                                                 int i,match=0;
2168                                                 char *str=g_strdup(at.u.str);
2169                                                 char *word=str;
2170                                                 do {
2171                                                         for (i = 0 ; i < 3 ; i++) {
2172                                                                 char *name=linguistics_expand_special(word,i);
2173                                                                 if (name && !ascii_cmp(name, map_search->search->u.str, map_search->partial))
2174                                                                         match=1;
2175                                                                 g_free(name);
2176                                                                 if (match)
2177                                                                         break;
2178                                                         }
2179                                                         if (match)
2180                                                                 break;
2181                                                         word=linguistics_next_word(word);
2182                                                 } while (word);
2183                                                 g_free(str);
2184                                                 if (match && !duplicate(map_search, it, attr_label)) {
2185                                                         item_coord_rewind(it);
2186                                                         return it;
2187                                                 }
2188                                         }
2189                                 }
2190                                 break;
2191                         case attr_house_number:
2192                                 //if (it->type == type_house_number)
2193                                 if ((it->type == type_house_number)||(type_house_number_interpolation_even)
2194                                         ||(type_house_number_interpolation_odd)
2195                                         ||(type_house_number_interpolation_all)
2196                                         )
2197                                 {
2198                                         // is it a housenumber?
2199                                         if (binfile_attr_get(it->priv_data, attr_house_number, &at))
2200                                         {
2201                                                 // match housenumber to our string
2202                                                 if (!ascii_cmp(at.u.str, map_search->search->u.str, map_search->partial))
2203                                                 {
2204                                                         //binfile_attr_get(it->priv_data, attr_street_name, &at);
2205                                                         //dbg(0,"hnnn B1 street_name=%s",at.u.str);
2206                                                         if (!duplicate(map_search, it, attr_house_number))
2207                                                         {
2208                                                                 binfile_attr_rewind(it->priv_data);
2209                                                                 return it;
2210                                                         }
2211                                                 }
2212                                         } else
2213                                                 return it;
2214                                 }
2215                                 continue;
2216                         default:
2217                                 return NULL;
2218                         }
2219                 }
2220                 if (!map_search->mr_item)
2221                         return NULL;
2222                 map_rect_destroy_binfile(map_search->mr);
2223                 if (!binmap_search_by_index(map_search->map, map_search->item, &map_search->mr))
2224                         return NULL;
2225         }
2226 }
2227
2228
2229 static void
2230 binmap_search_destroy(struct map_search_priv *ms)
2231 {
2232         if (ms->search_results)
2233                 g_hash_table_destroy(ms->search_results);
2234         if (ms->mr_item)
2235                 map_rect_destroy_binfile(ms->mr_item);
2236         if (ms->mr)
2237                 map_rect_destroy_binfile(ms->mr);
2238         g_free(ms);
2239 }
2240
2241 static int
2242 binmap_get_attr(struct map_priv *m, enum attr_type type, struct attr *attr)
2243 {
2244         attr->type=type;
2245         switch (type) {
2246         case attr_map_release:
2247                 if (m->map_release) {
2248                         attr->u.str=m->map_release;
2249                         return 1;
2250                 }
2251                 break;
2252         case attr_progress:
2253                 if (m->progress) {
2254                         attr->u.str=m->progress;
2255                         return 1;
2256                 }
2257         default:
2258                 break;
2259         }
2260         return 0;
2261 }
2262
2263 static int
2264 binmap_set_attr(struct map_priv *map, struct attr *attr)
2265 {
2266         switch (attr->type) {
2267         case attr_update:
2268                 map->download_enabled = attr->u.num;
2269                 return 1;
2270         default:
2271                 return 0;
2272         }
2273
2274 }
2275
2276 static struct map_methods map_methods_binfile = {
2277         projection_mg,
2278         "utf-8",
2279         map_destroy_binfile,
2280         map_rect_new_binfile,
2281         map_rect_destroy_binfile,
2282         map_rect_get_item_binfile,
2283         map_rect_get_item_byid_binfile,
2284         binmap_search_new,
2285         binmap_search_destroy,
2286         binmap_search_get_item,
2287         NULL,
2288         binmap_get_attr,
2289         binmap_set_attr,
2290 };
2291
2292 static int
2293 binfile_get_index(struct map_priv *m)
2294 {
2295         int len;
2296         int cde_index_size;
2297         int offset;
2298         struct zip_cd *cd;
2299
2300         len = strlen("index");
2301         cde_index_size = sizeof(struct zip_cd)+len;
2302         if (m->eoc64) 
2303                 offset = m->eoc64->zip64ecsz-cde_index_size;
2304         else
2305                 offset = m->eoc->zipecsz-cde_index_size;
2306         cd = binfile_read_cd(m, offset, len);
2307
2308         if (!cd) {
2309                 cde_index_size+=sizeof(struct zip_cd_ext);
2310                 if (m->eoc64)
2311                         offset = m->eoc64->zip64ecsz-cde_index_size;
2312                 else
2313                         offset = m->eoc->zipecsz-cde_index_size;
2314                 cd = binfile_read_cd(m, offset, len+sizeof(struct zip_cd_ext));
2315         }
2316         if (cd) {
2317                 if (cd->zipcfnl == len && !strncmp(cd->zipcfn, "index", len)) {
2318                         m->index_offset=offset;
2319                         m->index_cd=cd;
2320                         return 1;
2321                 }
2322         }
2323         offset=binfile_search_cd(m, 0, "index", 0, 0);
2324         if (offset == -1)
2325                 return 0;
2326         cd=binfile_read_cd(m, offset, -1);
2327         if (!cd)
2328                 return 0;
2329         m->index_offset=offset;
2330         m->index_cd=cd;
2331         return 1;
2332 }
2333
2334 static int
2335 map_binfile_zip_setup(struct map_priv *m, char *filename, int mmap)
2336 {
2337         struct zip_cd *first_cd;
2338         int i;
2339         if (!(m->eoc=binfile_read_eoc(m->fi))) {
2340                 dbg(0,"unable to read eoc\n");
2341                 return 0;
2342         }
2343         dbg_assert(m->eoc->zipedsk == m->eoc->zipecen);
2344         if (m->eoc->zipedsk && strlen(filename) > 3) {
2345                 char *tmpfilename=g_strdup(filename),*ext=tmpfilename+strlen(tmpfilename)-3;
2346                 m->fis=g_new(struct file *,m->eoc->zipedsk);
2347                 for (i = 0 ; i < m->eoc->zipedsk-1 ; i++) {
2348                         sprintf(ext,"b%02d",i+1);
2349                         m->fis[i]=file_create(tmpfilename, 0);
2350                         if (mmap)
2351                                 file_mmap(m->fis[i]);
2352                 }
2353                 m->fis[m->eoc->zipedsk-1]=m->fi;
2354                 g_free(tmpfilename);
2355         }
2356         dbg(1,"num_disk %d\n",m->eoc->zipedsk);
2357         m->eoc64=binfile_read_eoc64(m->fi);
2358         if (!binfile_get_index(m)) {
2359                 dbg(0,"no index found\n");
2360                 return 0;
2361         }
2362         if (!(first_cd=binfile_read_cd(m, 0, 0))) {
2363                 dbg(0,"unable to get first cd\n");
2364                 return 0;
2365         }
2366         m->cde_size=sizeof(struct zip_cd)+first_cd->zipcfnl+first_cd->zipcxtl;
2367         m->zip_members=m->index_offset/m->cde_size+1;
2368         dbg(1,"cde_size %d\n", m->cde_size);
2369         dbg(1,"members %d\n",m->zip_members);
2370         file_data_free(m->fi, (unsigned char *)first_cd);
2371         if (mmap)
2372                 file_mmap(m->fi);
2373         return 1;
2374 }
2375
2376
2377 #if 0
2378 static int
2379 map_binfile_download_initial(struct map_priv *m)
2380 {
2381         struct attr readwrite={attr_readwrite,{(void *)1}};
2382         struct attr create={attr_create,{(void *)1}};
2383         struct attr *attrs[4];
2384         struct file *out;
2385         long long woffset=0,planet_size;
2386         int size_ret;
2387         int cd1size,cdisize;
2388         long long cd1offset,cdioffset;
2389         struct zip64_eoc *zip64_eoc;
2390         struct zip64_eocl *zip64_eocl;
2391         struct zip_eoc *zip_eoc;
2392         struct zip_cd *cd1,*cdn,*cdi;
2393         int count,chunk,cdoffset=0;
2394         int mode=1;
2395         struct map_download *download=g_new0(struct map_download, 1);
2396
2397         attrs[0]=&readwrite;
2398         attrs[1]=&create;
2399         attrs[2]=NULL;
2400         download->file=file_create(m->filename,attrs);
2401         download->m=m;
2402         download_planet_size(download);
2403         download_eoc(download);
2404         download_directory_start(download);
2405         while (download_directory_do(download));
2406         download_directory_finish(download);
2407         download_initial_finish(download);
2408         m->fi=download->file;
2409         g_free(download);
2410         return 1;
2411         
2412
2413                 cd1size=sizeof(*cd1);
2414                 cd1offset=zip64_eoc->zip64eofst;
2415                 cd1=(struct zip_cd *)map_binfile_download_range(m, cd1offset, cd1size);
2416                 if (!cd1)
2417                         return 0;
2418                 cd1size=sizeof(*cd1)+binfile_cd_extra(cd1);
2419                 g_free(cd1);
2420                 cd1=(struct zip_cd *)map_binfile_download_range(m, cd1offset, cd1size);
2421                 if (!cd1) 
2422                         return 0;
2423                 cd1->zipcunc=0;
2424                 cdisize=sizeof(*cdi)+strlen("index")+cd1->zipcxtl;
2425                 cdioffset=zip64_eoc->zip64eofst+zip64_eoc->zip64ecsz-cdisize;
2426                 cdi=(struct zip_cd *)map_binfile_download_range(m, cdioffset, cdisize);
2427                 if (!cdi) {
2428                         g_free(cd1);
2429                         return 0;
2430                 }
2431                 cdi->zipcunc=0;
2432                 cdn=g_malloc0(cd1size*256);
2433
2434                 file_data_write(out, woffset, sizeof(*zip64_eoc), (unsigned char *)zip64_eoc);
2435                 woffset+=sizeof(*zip64_eoc);
2436                 cdoffset=woffset;
2437
2438                 file_data_write(out, woffset, cd1size, (unsigned char *)cd1);
2439                 woffset+=cd1size;
2440                 count=(cdioffset-cd1offset)/cd1size-1;
2441                 while (count > 0) {
2442                         if (count > 256)
2443                                 chunk=256;
2444                         else
2445                                 chunk=count;
2446                         file_data_write(out, woffset, cd1size*chunk, (unsigned char *)cdn);
2447                         woffset+=cd1size*chunk;
2448                         count-=chunk;
2449                 }
2450                 g_free(cdn);
2451                 g_free(cd1);
2452                 file_data_write(out, woffset, cdisize, (unsigned char *)cdi);
2453                 woffset+=cdisize;
2454
2455 }
2456 #endif
2457
2458 static int
2459 map_binfile_open(struct map_priv *m)
2460 {
2461         int *magic;
2462         struct map_rect_priv *mr;
2463         struct item *item;
2464         struct attr attr;
2465         struct attr readwrite={attr_readwrite, {(void *)1}};
2466         struct attr *attrs[]={&readwrite, NULL};
2467
2468         dbg(1,"file_create %s\n", m->filename);
2469         m->fi=file_create(m->filename, m->url?attrs:NULL);
2470         if (! m->fi && m->url)
2471                 return 0;
2472         if (! m->fi) {
2473                 dbg(0,"Failed to load '%s'\n", m->filename);
2474                 return 0;
2475         }
2476         if (m->check_version)
2477                 m->version=file_version(m->fi, m->check_version);
2478         magic=(int *)file_data_read(m->fi, 0, 4);
2479         if (!magic) {
2480                 file_destroy(m->fi);
2481                 m->fi=NULL;
2482                 return 0;
2483         }
2484         *magic = le32_to_cpu(*magic);
2485         if (*magic == zip_lfh_sig || *magic == zip_split_sig || *magic == zip_cd_sig || *magic == zip64_eoc_sig) {
2486                 if (!map_binfile_zip_setup(m, m->filename, m->flags & 1)) {
2487                         dbg(0,"invalid file format for '%s'\n", m->filename);
2488                         file_destroy(m->fi);
2489                         m->fi=NULL;
2490                         return 0;
2491                 }
2492         } else if (*magic == zip_lfh_sig_rev || *magic == zip_split_sig_rev || *magic == zip_cd_sig_rev || *magic == zip64_eoc_sig_rev) {
2493                 dbg(0,"endianness mismatch\n");
2494                 file_destroy(m->fi);
2495                 m->fi=NULL;
2496                 return 0;
2497         } else
2498                 file_mmap(m->fi);
2499         file_data_free(m->fi, (unsigned char *)magic);
2500         m->cachedir=g_strdup("/tmp/navit");
2501         m->map_version=0;
2502         mr=map_rect_new_binfile(m, NULL);
2503         if (mr) {
2504                 while ((item=map_rect_get_item_binfile(mr)) == &busy_item);
2505                 if (item && item->type == type_map_information)  {
2506                         if (binfile_attr_get(item->priv_data, attr_version, &attr))
2507                                 m->map_version=attr.u.num;
2508                         if (binfile_attr_get(item->priv_data, attr_map_release, &attr))
2509                                 m->map_release=g_strdup(attr.u.str);
2510                         if (m->url && binfile_attr_get(item->priv_data, attr_url, &attr)) {
2511                                 dbg(0,"url config %s map %s\n",m->url,attr.u.str);
2512                                 if (strcmp(m->url, attr.u.str)) 
2513                                         m->update_available=1;
2514                                 g_free(m->url);
2515                                 m->url=g_strdup(attr.u.str);
2516                         }
2517                 }
2518                 map_rect_destroy_binfile(mr);
2519                 if (m->map_version >= 16) {
2520                         dbg(0,"Warning: This map is incompatible with your navit version. Please update navit.\n");
2521                         return 0;
2522                 }
2523         }
2524         return 1;
2525 }
2526
2527 static void
2528 map_binfile_close(struct map_priv *m)
2529 {
2530         int i;
2531         file_data_free(m->fi, (unsigned char *)m->index_cd);
2532         file_data_free(m->fi, (unsigned char *)m->eoc);
2533         file_data_free(m->fi, (unsigned char *)m->eoc64);
2534         g_free(m->cachedir);
2535         g_free(m->map_release);
2536         if (m->fis) {
2537                 for (i = 0 ; i < m->eoc->zipedsk ; i++) {
2538                         file_destroy(m->fis[i]);
2539                 }
2540         } else
2541                 file_destroy(m->fi);
2542 }
2543
2544 static void
2545 map_binfile_destroy(struct map_priv *m)
2546 {
2547         g_free(m->filename);
2548         g_free(m->url);
2549         g_free(m->progress);
2550         g_free(m);
2551 }
2552
2553
2554 static void
2555 binfile_check_version(struct map_priv *m)
2556 {
2557         int version=-1;
2558         if (!m->check_version)
2559                 return;
2560         if (m->fi) 
2561                 version=file_version(m->fi, m->check_version);
2562         if (version != m->version) {
2563                 if (m->fi)
2564                         map_binfile_close(m);
2565                 map_binfile_open(m);
2566         }
2567 }
2568
2569
2570 static struct map_priv *
2571 map_new_binfile(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl)
2572 {
2573         struct map_priv *m;
2574         struct attr *data=attr_search(attrs, NULL, attr_data);
2575         struct attr *check_version,*map_pass,*flags,*url,*download_enabled;
2576         struct file_wordexp *wexp;
2577         char **wexp_data;
2578         if (! data)
2579                 return NULL;
2580
2581         wexp=file_wordexp_new(data->u.str);
2582         wexp_data=file_wordexp_get_array(wexp);
2583         dbg(1,"map_new_binfile %s\n", data->u.str);     
2584         *meth=map_methods_binfile;
2585
2586         m=g_new0(struct map_priv, 1);
2587         m->cbl=cbl;
2588         m->id=++map_id;
2589         m->filename=g_strdup(wexp_data[0]);
2590         file_wordexp_destroy(wexp);
2591         check_version=attr_search(attrs, NULL, attr_check_version);
2592         if (check_version) 
2593                 m->check_version=check_version->u.num;
2594         map_pass=attr_search(attrs, NULL, attr_map_pass);
2595         if (map_pass)
2596                 m->passwd=g_strdup(map_pass->u.str);
2597         flags=attr_search(attrs, NULL, attr_flags);
2598         if (flags)
2599                 m->flags=flags->u.num;
2600         url=attr_search(attrs, NULL, attr_url);
2601         if (url)
2602                 m->url=g_strdup(url->u.str);
2603         download_enabled = attr_search(attrs, NULL, attr_update);
2604         if (download_enabled)
2605                 m->download_enabled=download_enabled->u.num;
2606
2607         if (!map_binfile_open(m) && !m->check_version && !m->url) {
2608                 map_binfile_destroy(m);
2609                 m=NULL;
2610         } else {
2611                 load_changes(m);
2612         }
2613         return m;
2614 }
2615
2616 void
2617 plugin_init(void)
2618 {
2619         dbg(1,"binfile: plugin_init\n");
2620         if (sizeof(struct zip_cd) != 46) {
2621                 dbg(0,"error: sizeof(struct zip_cd)=%d\n",sizeof(struct zip_cd));
2622         }
2623         plugin_register_map_type("binfile", map_new_binfile);
2624 }
2625