diff options
Diffstat (limited to 'navit/map/binfile/binfile.c')
-rw-r--r-- | navit/map/binfile/binfile.c | 5066 |
1 files changed, 2449 insertions, 2617 deletions
diff --git a/navit/map/binfile/binfile.c b/navit/map/binfile/binfile.c index 93cbbd466..7cc707ac8 100644 --- a/navit/map/binfile/binfile.c +++ b/navit/map/binfile/binfile.c @@ -62,40 +62,40 @@ static int map_id; * used for working with the data. */ struct tile { - int *start; //!< Memory address of the buffer containing the tile data (the actual map data). - int *end; //!< First memory address not belonging to the tile data. - /**< Thus tile->end - tile->start represents the size of the tile data - * in multiples of 4 Bytes. - */ - int *pos; //!< Pointer to current position (start of current item) inside the tile data. - int *pos_coord_start; //!< Pointer to the first element inside the current item that is a coordinate. - /**< That is the first position after the header of an - * item. The header holds 3 entries each 32bit wide integers: - * header[0] holds the size of the whole item (excluding this size field) - * header[1] holds the type of the item - * header[2] holds the size of the coordinates in the tile - */ - int *pos_coord; //!< Current position in the coordinates region of the current item. - int *pos_attr_start; //!< Pointer to the first attr data structure of the current item. - int *pos_attr; //!< Current position in the attr region of the current item. - int *pos_next; //!< Pointer to the next item (the item which follows the "current item" as indicated by *pos). - struct file *fi; //!< The file from which this tile was loaded. - int zipfile_num; - int mode; + int *start; //!< Memory address of the buffer containing the tile data (the actual map data). + int *end; //!< First memory address not belonging to the tile data. + /**< Thus tile->end - tile->start represents the size of the tile data + * in multiples of 4 Bytes. + */ + int *pos; //!< Pointer to current position (start of current item) inside the tile data. + int *pos_coord_start; //!< Pointer to the first element inside the current item that is a coordinate. + /**< That is the first position after the header of an + * item. The header holds 3 entries each 32bit wide integers: + * header[0] holds the size of the whole item (excluding this size field) + * header[1] holds the type of the item + * header[2] holds the size of the coordinates in the tile + */ + int *pos_coord; //!< Current position in the coordinates region of the current item. + int *pos_attr_start; //!< Pointer to the first attr data structure of the current item. + int *pos_attr; //!< Current position in the attr region of the current item. + int *pos_next; //!< Pointer to the next item (the item which follows the "current item" as indicated by *pos). + struct file *fi; //!< The file from which this tile was loaded. + int zipfile_num; + int mode; }; struct map_download { - int state; - struct map_priv *m; - struct map_rect_priv *mr; - struct file *http,*file; - int zipfile,toffset,tlength,progress,read,dl_size; - long long offset,start_offset,cd1offset,size; - struct zip64_eoc *zip64_eoc; - struct zip64_eocl *zip64_eocl; - struct zip_eoc *zip_eoc; - struct zip_cd *cd_copy,*cd; + int state; + struct map_priv *m; + struct map_rect_priv *mr; + struct file *http,*file; + int zipfile,toffset,tlength,progress,read,dl_size; + long long offset,start_offset,cd1offset,size; + struct zip64_eoc *zip64_eoc; + struct zip64_eocl *zip64_eocl; + struct zip_eoc *zip_eoc; + struct zip_cd *cd_copy,*cd; }; /** @@ -103,56 +103,56 @@ struct map_download { * */ struct map_priv { - int id; - char *filename; //!< Filename of the binfile. - char *cachedir; - struct file *fi,*http; - struct file **fis; - struct zip_cd *index_cd; - int index_offset; - int cde_size; - struct zip_eoc *eoc; - struct zip64_eoc *eoc64; - int zip_members; - unsigned char *search_data; - int search_offset; - int search_size; - int version; - int check_version; - int map_version; - GHashTable *changes; - char *map_release; - int flags; - char *url; - int update_available; - char *progress; - struct callback_list *cbl; - struct map_download *download; - int redirect; - long download_enabled; - int last_searched_town_id_hi; - int last_searched_town_id_lo; + int id; + char *filename; //!< Filename of the binfile. + char *cachedir; + struct file *fi,*http; + struct file **fis; + struct zip_cd *index_cd; + int index_offset; + int cde_size; + struct zip_eoc *eoc; + struct zip64_eoc *eoc64; + int zip_members; + unsigned char *search_data; + int search_offset; + int search_size; + int version; + int check_version; + int map_version; + GHashTable *changes; + char *map_release; + int flags; + char *url; + int update_available; + char *progress; + struct callback_list *cbl; + struct map_download *download; + int redirect; + long download_enabled; + int last_searched_town_id_hi; + int last_searched_town_id_lo; }; struct map_rect_priv { - int *start; - int *end; - enum attr_type attr_last; - int label; - int *label_attr[5]; - struct map_selection *sel; - struct map_priv *m; - struct item item; - int tile_depth; - struct tile tiles[8]; - struct tile *t; - int country_id; - char *url; - struct attr attrs[8]; - int status; - struct map_search_priv *msp; + int *start; + int *end; + enum attr_type attr_last; + int label; + int *label_attr[5]; + struct map_selection *sel; + struct map_priv *m; + struct item item; + int tile_depth; + struct tile tiles[8]; + struct tile *t; + int country_id; + char *url; + struct attr attrs[8]; + int status; + struct map_search_priv *msp; #ifdef DEBUG_SIZE - int size; + int size; #endif }; @@ -162,18 +162,18 @@ struct map_rect_priv { * when starting a search, and is used for retrieving results. */ struct map_search_priv { - struct map_priv *map; /**< Map to search in. */ - struct map_rect_priv *mr; /**< Map rectangle to search inside. */ - struct map_rect_priv *mr_item; - struct item *item; - struct attr search; /**< Attribute specifying what to search for. */ - struct map_selection ms; - GList *boundaries; - int partial; /**< Find partial matches? */ - int mode; - struct coord_rect rect_new; - char *parent_name; - GHashTable *search_results; + struct map_priv *map; /**< Map to search in. */ + struct map_rect_priv *mr; /**< Map rectangle to search inside. */ + struct map_rect_priv *mr_item; + struct item *item; + struct attr search; /**< Attribute specifying what to search for. */ + struct map_selection ms; + GList *boundaries; + int partial; /**< Find partial matches? */ + int mode; + struct coord_rect rect_new; + char *parent_name; + GHashTable *search_results; }; @@ -184,127 +184,120 @@ static int map_binfile_open(struct map_priv *m); static void map_binfile_destroy(struct map_priv *m); static void lfh_to_cpu(struct zip_lfh *lfh) { - dbg_assert(lfh != NULL); - if (lfh->ziplocsig != zip_lfh_sig) { - lfh->ziplocsig = le32_to_cpu(lfh->ziplocsig); - lfh->zipver = le16_to_cpu(lfh->zipver); - lfh->zipgenfld = le16_to_cpu(lfh->zipgenfld); - lfh->zipmthd = le16_to_cpu(lfh->zipmthd); - lfh->ziptime = le16_to_cpu(lfh->ziptime); - lfh->zipdate = le16_to_cpu(lfh->zipdate); - lfh->zipcrc = le32_to_cpu(lfh->zipcrc); - lfh->zipsize = le32_to_cpu(lfh->zipsize); - lfh->zipuncmp = le32_to_cpu(lfh->zipuncmp); - lfh->zipfnln = le16_to_cpu(lfh->zipfnln); - lfh->zipxtraln = le16_to_cpu(lfh->zipxtraln); - } + dbg_assert(lfh != NULL); + if (lfh->ziplocsig != zip_lfh_sig) { + lfh->ziplocsig = le32_to_cpu(lfh->ziplocsig); + lfh->zipver = le16_to_cpu(lfh->zipver); + lfh->zipgenfld = le16_to_cpu(lfh->zipgenfld); + lfh->zipmthd = le16_to_cpu(lfh->zipmthd); + lfh->ziptime = le16_to_cpu(lfh->ziptime); + lfh->zipdate = le16_to_cpu(lfh->zipdate); + lfh->zipcrc = le32_to_cpu(lfh->zipcrc); + lfh->zipsize = le32_to_cpu(lfh->zipsize); + lfh->zipuncmp = le32_to_cpu(lfh->zipuncmp); + lfh->zipfnln = le16_to_cpu(lfh->zipfnln); + lfh->zipxtraln = le16_to_cpu(lfh->zipxtraln); + } } static void cd_to_cpu(struct zip_cd *zcd) { - dbg_assert(zcd != NULL); - if (zcd->zipcensig != zip_cd_sig) { - zcd->zipcensig = le32_to_cpu(zcd->zipcensig); - zcd->zipccrc = le32_to_cpu(zcd->zipccrc); - zcd->zipcsiz = le32_to_cpu(zcd->zipcsiz); - zcd->zipcunc = le32_to_cpu(zcd->zipcunc); - zcd->zipcfnl = le16_to_cpu(zcd->zipcfnl); - zcd->zipcxtl = le16_to_cpu(zcd->zipcxtl); - zcd->zipccml = le16_to_cpu(zcd->zipccml); - zcd->zipdsk = le16_to_cpu(zcd->zipdsk); - zcd->zipint = le16_to_cpu(zcd->zipint); - zcd->zipext = le32_to_cpu(zcd->zipext); - zcd->zipofst = le32_to_cpu(zcd->zipofst); - } + dbg_assert(zcd != NULL); + if (zcd->zipcensig != zip_cd_sig) { + zcd->zipcensig = le32_to_cpu(zcd->zipcensig); + zcd->zipccrc = le32_to_cpu(zcd->zipccrc); + zcd->zipcsiz = le32_to_cpu(zcd->zipcsiz); + zcd->zipcunc = le32_to_cpu(zcd->zipcunc); + zcd->zipcfnl = le16_to_cpu(zcd->zipcfnl); + zcd->zipcxtl = le16_to_cpu(zcd->zipcxtl); + zcd->zipccml = le16_to_cpu(zcd->zipccml); + zcd->zipdsk = le16_to_cpu(zcd->zipdsk); + zcd->zipint = le16_to_cpu(zcd->zipint); + zcd->zipext = le32_to_cpu(zcd->zipext); + zcd->zipofst = le32_to_cpu(zcd->zipofst); + } } static void eoc_to_cpu(struct zip_eoc *eoc) { - dbg_assert(eoc != NULL); - if (eoc->zipesig != zip_eoc_sig) { - eoc->zipesig = le32_to_cpu(eoc->zipesig); - eoc->zipedsk = le16_to_cpu(eoc->zipedsk); - eoc->zipecen = le16_to_cpu(eoc->zipecen); - eoc->zipenum = le16_to_cpu(eoc->zipenum); - eoc->zipecenn = le16_to_cpu(eoc->zipecenn); - eoc->zipecsz = le32_to_cpu(eoc->zipecsz); - eoc->zipeofst = le32_to_cpu(eoc->zipeofst); - eoc->zipecoml = le16_to_cpu(eoc->zipecoml); - } + dbg_assert(eoc != NULL); + if (eoc->zipesig != zip_eoc_sig) { + eoc->zipesig = le32_to_cpu(eoc->zipesig); + eoc->zipedsk = le16_to_cpu(eoc->zipedsk); + eoc->zipecen = le16_to_cpu(eoc->zipecen); + eoc->zipenum = le16_to_cpu(eoc->zipenum); + eoc->zipecenn = le16_to_cpu(eoc->zipecenn); + eoc->zipecsz = le32_to_cpu(eoc->zipecsz); + eoc->zipeofst = le32_to_cpu(eoc->zipeofst); + eoc->zipecoml = le16_to_cpu(eoc->zipecoml); + } } static void binfile_check_version(struct map_priv *m); -static struct zip_eoc * -binfile_read_eoc(struct file *fi) -{ - struct zip_eoc *eoc; - eoc=(struct zip_eoc *)file_data_read(fi,fi->size-sizeof(struct zip_eoc), sizeof(struct zip_eoc)); - if (eoc) { - eoc_to_cpu(eoc); - dbg(lvl_debug,"sig 0x%x\n", eoc->zipesig); - if (eoc->zipesig != zip_eoc_sig) { - dbg(lvl_error,"map file %s: eoc signature check failed: 0x%x vs 0x%x\n", fi->name, eoc->zipesig,zip_eoc_sig); - file_data_free(fi,(unsigned char *)eoc); - eoc=NULL; - } - } - return eoc; -} - -static struct zip64_eoc * -binfile_read_eoc64(struct file *fi) -{ - struct zip64_eocl *eocl; - struct zip64_eoc *eoc; - eocl=(struct zip64_eocl *)file_data_read(fi,fi->size-sizeof(struct zip_eoc)-sizeof(struct zip64_eocl), sizeof(struct zip64_eocl)); - if (!eocl) - return NULL; - dbg(lvl_debug,"sig 0x%x\n", eocl->zip64lsig); - if (eocl->zip64lsig != zip64_eocl_sig) { - file_data_free(fi,(unsigned char *)eocl); - dbg(lvl_warning,"map file %s: eocl wrong\n", fi->name); - return NULL; - } - eoc=(struct zip64_eoc *)file_data_read(fi,eocl->zip64lofst, sizeof(struct zip64_eoc)); - if (eoc) { - if (eoc->zip64esig != zip64_eoc_sig) { - file_data_free(fi,(unsigned char *)eoc); - dbg(lvl_warning,"map file %s: eoc wrong\n", fi->name); - eoc=NULL; - } - dbg(lvl_debug,"eoc64 ok 0x"LONGLONG_HEX_FMT " 0x"LONGLONG_HEX_FMT "\n",eoc->zip64eofst,eoc->zip64ecsz); - } - file_data_free(fi,(unsigned char *)eocl); - return eoc; -} - -static int -binfile_cd_extra(struct zip_cd *cd) -{ - return cd->zipcfnl+cd->zipcxtl; -} - -static struct zip_cd * -binfile_read_cd(struct map_priv *m, int offset, int len) -{ - struct zip_cd *cd; - long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst; - if (len == -1) { - cd=(struct zip_cd *)file_data_read(m->fi,cdoffset+offset, sizeof(*cd)); - cd_to_cpu(cd); - len=binfile_cd_extra(cd); - file_data_free(m->fi,(unsigned char *)cd); - } - cd=(struct zip_cd *)file_data_read(m->fi,cdoffset+offset, sizeof(*cd)+len); - if (cd) { - dbg(lvl_debug,"cd at "LONGLONG_FMT" %zu bytes\n",cdoffset+offset, sizeof(*cd)+len); - cd_to_cpu(cd); - dbg(lvl_debug,"sig 0x%x\n", cd->zipcensig); - if (cd->zipcensig != zip_cd_sig) { - file_data_free(m->fi,(unsigned char *)cd); - cd=NULL; - } - } - return cd; +static struct zip_eoc *binfile_read_eoc(struct file *fi) { + struct zip_eoc *eoc; + eoc=(struct zip_eoc *)file_data_read(fi,fi->size-sizeof(struct zip_eoc), sizeof(struct zip_eoc)); + if (eoc) { + eoc_to_cpu(eoc); + dbg(lvl_debug,"sig 0x%x", eoc->zipesig); + if (eoc->zipesig != zip_eoc_sig) { + dbg(lvl_error,"map file %s: eoc signature check failed: 0x%x vs 0x%x", fi->name, eoc->zipesig,zip_eoc_sig); + file_data_free(fi,(unsigned char *)eoc); + eoc=NULL; + } + } + return eoc; +} + +static struct zip64_eoc *binfile_read_eoc64(struct file *fi) { + struct zip64_eocl *eocl; + struct zip64_eoc *eoc; + eocl=(struct zip64_eocl *)file_data_read(fi,fi->size-sizeof(struct zip_eoc)-sizeof(struct zip64_eocl), + sizeof(struct zip64_eocl)); + if (!eocl) + return NULL; + dbg(lvl_debug,"sig 0x%x", eocl->zip64lsig); + if (eocl->zip64lsig != zip64_eocl_sig) { + file_data_free(fi,(unsigned char *)eocl); + dbg(lvl_warning,"map file %s: eocl wrong", fi->name); + return NULL; + } + eoc=(struct zip64_eoc *)file_data_read(fi,eocl->zip64lofst, sizeof(struct zip64_eoc)); + if (eoc) { + if (eoc->zip64esig != zip64_eoc_sig) { + file_data_free(fi,(unsigned char *)eoc); + dbg(lvl_warning,"map file %s: eoc wrong", fi->name); + eoc=NULL; + } + dbg(lvl_debug,"eoc64 ok 0x"LONGLONG_HEX_FMT " 0x"LONGLONG_HEX_FMT "",eoc->zip64eofst,eoc->zip64ecsz); + } + file_data_free(fi,(unsigned char *)eocl); + return eoc; +} + +static int binfile_cd_extra(struct zip_cd *cd) { + return cd->zipcfnl+cd->zipcxtl; +} + +static struct zip_cd *binfile_read_cd(struct map_priv *m, int offset, int len) { + struct zip_cd *cd; + long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst; + if (len == -1) { + cd=(struct zip_cd *)file_data_read(m->fi,cdoffset+offset, sizeof(*cd)); + cd_to_cpu(cd); + len=binfile_cd_extra(cd); + file_data_free(m->fi,(unsigned char *)cd); + } + cd=(struct zip_cd *)file_data_read(m->fi,cdoffset+offset, sizeof(*cd)+len); + if (cd) { + dbg(lvl_debug,"cd at "LONGLONG_FMT" %zu bytes",cdoffset+offset, sizeof(*cd)+len); + cd_to_cpu(cd); + dbg(lvl_debug,"sig 0x%x", cd->zipcensig); + if (cd->zipcensig != zip_cd_sig) { + file_data_free(m->fi,(unsigned char *)cd); + cd=NULL; + } + } + return cd; } /** @@ -314,18 +307,16 @@ binfile_read_cd(struct map_priv *m, int offset, int len) * @param cd pointer to zip central directory structure * @return pointer to ZIP64 extra field, or NULL if not available */ -static struct zip_cd_ext * -binfile_cd_ext(struct zip_cd *cd) -{ - struct zip_cd_ext *ext; - if (cd->zipofst != zip_size_64bit_placeholder) - return NULL; - if (cd->zipcxtl != sizeof(*ext)) - return NULL; - ext=(struct zip_cd_ext *)((unsigned char *)cd+sizeof(*cd)+cd->zipcfnl); - if (ext->tag != zip_extra_header_id_zip64 || ext->size != 8) - return NULL; - return ext; +static struct zip_cd_ext *binfile_cd_ext(struct zip_cd *cd) { + struct zip_cd_ext *ext; + if (cd->zipofst != zip_size_64bit_placeholder) + return NULL; + if (cd->zipcxtl != sizeof(*ext)) + return NULL; + ext=(struct zip_cd_ext *)((unsigned char *)cd+sizeof(*cd)+cd->zipcfnl); + if (ext->tag != zip_extra_header_id_zip64 || ext->size != 8) + return NULL; + return ext; } /** @@ -333,148 +324,133 @@ binfile_cd_ext(struct zip_cd *cd) * @return Offset of local file header in zip file. * Will use ZIP64 data if present. */ -static long long -binfile_cd_offset(struct zip_cd *cd) -{ - struct zip_cd_ext *ext=binfile_cd_ext(cd); - if (ext) - return ext->zipofst; - else - return cd->zipofst; -} - -static struct zip_lfh * -binfile_read_lfh(struct file *fi, long long offset) -{ - struct zip_lfh *lfh; - - lfh=(struct zip_lfh *)(file_data_read(fi,offset,sizeof(struct zip_lfh))); - if (lfh) { - lfh_to_cpu(lfh); - if (lfh->ziplocsig != zip_lfh_sig) { - file_data_free(fi,(unsigned char *)lfh); - lfh=NULL; - } - } - return lfh; -} - -static unsigned char * -binfile_read_content(struct map_priv *m, struct file *fi, long long offset, struct zip_lfh *lfh) -{ - unsigned char *ret=NULL; - - offset+=sizeof(struct zip_lfh)+lfh->zipfnln; - switch (lfh->zipmthd) { - case 0: - offset+=lfh->zipxtraln; - ret=file_data_read(fi,offset, lfh->zipuncmp); - break; - case 8: - offset+=lfh->zipxtraln; - ret=file_data_read_compressed(fi,offset, lfh->zipsize, lfh->zipuncmp); - break; - default: - dbg(lvl_error,"map file %s: unknown compression method %d\n", fi->name, lfh->zipmthd); - } - return ret; -} - -static int -binfile_search_cd(struct map_priv *m, int offset, char *name, int partial, int skip) -{ - int size=4096; - int end=m->eoc64?m->eoc64->zip64ecsz:m->eoc->zipecsz; - int len=strlen(name); - long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst; - struct zip_cd *cd; +static long long binfile_cd_offset(struct zip_cd *cd) { + struct zip_cd_ext *ext=binfile_cd_ext(cd); + if (ext) + return ext->zipofst; + else + return cd->zipofst; +} + +static struct zip_lfh *binfile_read_lfh(struct file *fi, long long offset) { + struct zip_lfh *lfh; + + lfh=(struct zip_lfh *)(file_data_read(fi,offset,sizeof(struct zip_lfh))); + if (lfh) { + lfh_to_cpu(lfh); + if (lfh->ziplocsig != zip_lfh_sig) { + file_data_free(fi,(unsigned char *)lfh); + lfh=NULL; + } + } + return lfh; +} + +static unsigned char *binfile_read_content(struct map_priv *m, struct file *fi, long long offset, struct zip_lfh *lfh) { + unsigned char *ret=NULL; + + offset+=sizeof(struct zip_lfh)+lfh->zipfnln; + switch (lfh->zipmthd) { + case 0: + offset+=lfh->zipxtraln; + ret=file_data_read(fi,offset, lfh->zipuncmp); + break; + case 8: + offset+=lfh->zipxtraln; + ret=file_data_read_compressed(fi,offset, lfh->zipsize, lfh->zipuncmp); + break; + default: + dbg(lvl_error,"map file %s: unknown compression method %d", fi->name, lfh->zipmthd); + } + return ret; +} + +static int binfile_search_cd(struct map_priv *m, int offset, char *name, int partial, int skip) { + int size=4096; + int end=m->eoc64?m->eoc64->zip64ecsz:m->eoc->zipecsz; + int len=strlen(name); + long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst; + struct zip_cd *cd; #if 0 - dbg(lvl_debug,"end=%d\n",end); + dbg(lvl_debug,"end=%d",end); #endif - while (offset < end) { - cd=(struct zip_cd *)(m->search_data+offset-m->search_offset); - if (! m->search_data || - m->search_offset > offset || - offset-m->search_offset+sizeof(*cd) > m->search_size || - offset-m->search_offset+sizeof(*cd)+cd->zipcfnl+cd->zipcxtl > m->search_size - ) { + while (offset < end) { + cd=(struct zip_cd *)(m->search_data+offset-m->search_offset); + if (! m->search_data || + m->search_offset > offset || + offset-m->search_offset+sizeof(*cd) > m->search_size || + offset-m->search_offset+sizeof(*cd)+cd->zipcfnl+cd->zipcxtl > m->search_size + ) { #if 0 - dbg(lvl_debug,"reload %p %d %d\n", m->search_data, m->search_offset, offset); + dbg(lvl_debug,"reload %p %d %d", m->search_data, m->search_offset, offset); #endif - if (m->search_data) - file_data_free(m->fi,m->search_data); - m->search_offset=offset; - m->search_size=end-offset; - if (m->search_size > size) - m->search_size=size; - m->search_data=file_data_read(m->fi,cdoffset+m->search_offset,m->search_size); - cd=(struct zip_cd *)m->search_data; - } + if (m->search_data) + file_data_free(m->fi,m->search_data); + m->search_offset=offset; + m->search_size=end-offset; + if (m->search_size > size) + m->search_size=size; + m->search_data=file_data_read(m->fi,cdoffset+m->search_offset,m->search_size); + cd=(struct zip_cd *)m->search_data; + } #if 0 - dbg(lvl_debug,"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); - dbg(lvl_debug,"offset=%d fn='%s'\n",offset,cd->zipcfn); + dbg(lvl_debug,"offset=%d search_offset=%d search_size=%d search_data=%p cd=%p", offset, m->search_offset, + m->search_size, m->search_data, cd); + dbg(lvl_debug,"offset=%d fn='%s'",offset,cd->zipcfn); #endif - if (!skip && - (partial || cd->zipcfnl == len) && - !strncmp(cd->zipcfn, name, len)) - return offset; - skip=0; - offset+=sizeof(*cd)+cd->zipcfnl+cd->zipcxtl+cd->zipccml; -; - } - return -1; -} - -static void -map_destroy_binfile(struct map_priv *m) -{ - dbg(lvl_debug,"map_destroy_binfile\n"); - if (m->fi) - map_binfile_close(m); - map_binfile_destroy(m); -} - -static void -binfile_coord_rewind(void *priv_data) -{ - struct map_rect_priv *mr=priv_data; - struct tile *t=mr->t; - t->pos_coord=t->pos_coord_start; -} - -static inline int -binfile_coord_left(void *priv_data) -{ - struct map_rect_priv *mr=priv_data; - struct tile *t=mr->t; - return (t->pos_attr_start-t->pos_coord)/2; -} - -static int -binfile_coord_get(void *priv_data, struct coord *c, int count) -{ - struct map_rect_priv *mr=priv_data; - struct tile *t=mr->t; - int max,ret=0; - max=binfile_coord_left(priv_data); - if (count > max) - count=max; + if (!skip && + (partial || cd->zipcfnl == len) && + !strncmp(cd->zipcfn, name, len)) + return offset; + skip=0; + offset+=sizeof(*cd)+cd->zipcfnl+cd->zipcxtl+cd->zipccml; + ; + } + return -1; +} + +static void map_destroy_binfile(struct map_priv *m) { + dbg(lvl_debug,"map_destroy_binfile"); + if (m->fi) + map_binfile_close(m); + map_binfile_destroy(m); +} + +static void binfile_coord_rewind(void *priv_data) { + struct map_rect_priv *mr=priv_data; + struct tile *t=mr->t; + t->pos_coord=t->pos_coord_start; +} + +static inline int binfile_coord_left(void *priv_data) { + struct map_rect_priv *mr=priv_data; + struct tile *t=mr->t; + return (t->pos_attr_start-t->pos_coord)/2; +} + +static int binfile_coord_get(void *priv_data, struct coord *c, int count) { + struct map_rect_priv *mr=priv_data; + struct tile *t=mr->t; + int max,ret=0; + max=binfile_coord_left(priv_data); + if (count > max) + count=max; #if __BYTE_ORDER == __LITTLE_ENDIAN - memcpy(c, t->pos_coord, count*sizeof(struct coord)); + memcpy(c, t->pos_coord, count*sizeof(struct coord)); #else - { - int i=0,end=count*sizeof(struct coord)/sizeof(int); - int *src=(int *)t->pos_coord; - int *dst=(int *)c; - while (i++ < end) { - *dst++=le32_to_cpu(*src); - src++; - } - } + { + int i=0,end=count*sizeof(struct coord)/sizeof(int); + int *src=(int *)t->pos_coord; + int *dst=(int *)c; + while (i++ < end) { + *dst++=le32_to_cpu(*src); + src++; + } + } #endif - t->pos_coord+=count*2; - ret=count; - return ret; + t->pos_coord+=count*2; + ret=count; + return ret; } /** @@ -482,1689 +458,1582 @@ binfile_coord_get(void *priv_data, struct coord *c, int count) * @param * @return */ -static void -binfile_attr_rewind(void *priv_data) -{ - struct map_rect_priv *mr=priv_data; - struct tile *t=mr->t; - t->pos_attr=t->pos_attr_start; - mr->label=0; - memset(mr->label_attr, 0, sizeof(mr->label_attr)); - -} - -static char * -binfile_extract(struct map_priv *m, char *dir, char *filename, int partial) -{ - char *full,*fulld,*sep; - unsigned char *start; - int len,offset=m->index_offset; - struct zip_cd *cd; - struct zip_lfh *lfh; - FILE *f; - - for (;;) { - offset=binfile_search_cd(m, offset, filename, partial, 1); - if (offset == -1) - break; - cd=binfile_read_cd(m, offset, -1); - len=strlen(dir)+1+cd->zipcfnl+1; - full=g_malloc(len); - strcpy(full,dir); - strcpy(full+strlen(full),"/"); - strncpy(full+strlen(full),cd->zipcfn,cd->zipcfnl); - full[len-1]='\0'; - fulld=g_strdup(full); - sep=strrchr(fulld, '/'); - if (sep) { - *sep='\0'; - file_mkdir(fulld, 1); - } - if (full[len-2] != '/') { - lfh=binfile_read_lfh(m->fi, binfile_cd_offset(cd)); - start=binfile_read_content(m, m->fi, binfile_cd_offset(cd), lfh); - dbg(lvl_debug,"fopen '%s'\n", full); - f=fopen(full,"w"); - fwrite(start, lfh->zipuncmp, 1, f); - fclose(f); - file_data_free(m->fi, start); - file_data_free(m->fi, (unsigned char *)lfh); - } - file_data_free(m->fi, (unsigned char *)cd); - g_free(fulld); - g_free(full); - if (! partial) - break; - } - - return g_strdup_printf("%s/%s",dir,filename); -} - -static int -binfile_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) -{ - struct map_rect_priv *mr=priv_data; - struct tile *t=mr->t; - enum attr_type type; - int i,size; - - if (attr_type != mr->attr_last) { - t->pos_attr=t->pos_attr_start; - mr->attr_last=attr_type; - } - while (t->pos_attr < t->pos_next) { - size=le32_to_cpu(*(t->pos_attr++)); - type=le32_to_cpu(t->pos_attr[0]); - if (type == attr_label) - mr->label=1; - if (type == attr_house_number) - mr->label_attr[0]=t->pos_attr; - if (type == attr_street_name) - mr->label_attr[1]=t->pos_attr; - if (type == attr_street_name_systematic) - mr->label_attr[2]=t->pos_attr; - if (type == attr_district_name && mr->item.type < type_line) - mr->label_attr[3]=t->pos_attr; - if (type == attr_town_name && mr->item.type < type_line) - mr->label_attr[4]=t->pos_attr; - if (type == attr_type || attr_type == attr_any) { - if (attr_type == attr_any) { - dbg(lvl_debug,"pos %p attr %s size %d\n", t->pos_attr-1, attr_to_name(type), size); - } - attr->type=type; - if (ATTR_IS_GROUP(type)) { - int i=0; - int *subpos=t->pos_attr+1; - int size_rem=size-1; - i=0; - while (size_rem > 0 && i < 7) { - int subsize=le32_to_cpu(*subpos++); - int subtype=le32_to_cpu(subpos[0]); - mr->attrs[i].type=subtype; - attr_data_set_le(&mr->attrs[i], subpos+1); - subpos+=subsize; - size_rem-=subsize+1; - i++; - } - mr->attrs[i].type=type_none; - mr->attrs[i].u.data=NULL; - attr->u.attrs=mr->attrs; - } else { - attr_data_set_le(attr, t->pos_attr+1); - if (type == attr_url_local) { - g_free(mr->url); - mr->url=binfile_extract(mr->m, mr->m->cachedir, attr->u.str, 1); - attr->u.str=mr->url; - } - if (type == attr_flags && mr->m->map_version < 1) - attr->u.num |= AF_CAR; - } - t->pos_attr+=size; - return 1; - } else { - t->pos_attr+=size; - } - } - if (!mr->label && (attr_type == attr_any || attr_type == attr_label)) { - for (i = 0 ; i < sizeof(mr->label_attr)/sizeof(int *) ; i++) { - if (mr->label_attr[i]) { - mr->label=1; - attr->type=attr_label; - attr_data_set_le(attr,mr->label_attr[i]+1); - return 1; - } - } - } - return 0; +static void binfile_attr_rewind(void *priv_data) { + struct map_rect_priv *mr=priv_data; + struct tile *t=mr->t; + t->pos_attr=t->pos_attr_start; + mr->label=0; + memset(mr->label_attr, 0, sizeof(mr->label_attr)); + +} + +static char *binfile_extract(struct map_priv *m, char *dir, char *filename, int partial) { + char *full,*fulld,*sep; + unsigned char *start; + int len,offset=m->index_offset; + struct zip_cd *cd; + struct zip_lfh *lfh; + FILE *f; + + for (;;) { + offset=binfile_search_cd(m, offset, filename, partial, 1); + if (offset == -1) + break; + cd=binfile_read_cd(m, offset, -1); + len=strlen(dir)+1+cd->zipcfnl+1; + full=g_malloc(len); + strcpy(full,dir); + strcpy(full+strlen(full),"/"); + strncpy(full+strlen(full),cd->zipcfn,cd->zipcfnl); + full[len-1]='\0'; + fulld=g_strdup(full); + sep=strrchr(fulld, '/'); + if (sep) { + *sep='\0'; + file_mkdir(fulld, 1); + } + if (full[len-2] != '/') { + lfh=binfile_read_lfh(m->fi, binfile_cd_offset(cd)); + start=binfile_read_content(m, m->fi, binfile_cd_offset(cd), lfh); + dbg(lvl_debug,"fopen '%s'", full); + f=fopen(full,"w"); + fwrite(start, lfh->zipuncmp, 1, f); + fclose(f); + file_data_free(m->fi, start); + file_data_free(m->fi, (unsigned char *)lfh); + } + file_data_free(m->fi, (unsigned char *)cd); + g_free(fulld); + g_free(full); + if (! partial) + break; + } + + return g_strdup_printf("%s/%s",dir,filename); +} + +static int binfile_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) { + struct map_rect_priv *mr=priv_data; + struct tile *t=mr->t; + enum attr_type type; + int i,size; + + if (attr_type != mr->attr_last) { + t->pos_attr=t->pos_attr_start; + mr->attr_last=attr_type; + } + while (t->pos_attr < t->pos_next) { + size=le32_to_cpu(*(t->pos_attr++)); + type=le32_to_cpu(t->pos_attr[0]); + if (type == attr_label) + mr->label=1; + if (type == attr_house_number) + mr->label_attr[0]=t->pos_attr; + if (type == attr_street_name) + mr->label_attr[1]=t->pos_attr; + if (type == attr_street_name_systematic) + mr->label_attr[2]=t->pos_attr; + if (type == attr_district_name && mr->item.type < type_line) + mr->label_attr[3]=t->pos_attr; + if (type == attr_town_name && mr->item.type < type_line) + mr->label_attr[4]=t->pos_attr; + if (type == attr_type || attr_type == attr_any) { + if (attr_type == attr_any) { + dbg(lvl_debug,"pos %p attr %s size %d", t->pos_attr-1, attr_to_name(type), size); + } + attr->type=type; + if (ATTR_IS_GROUP(type)) { + int i=0; + int *subpos=t->pos_attr+1; + int size_rem=size-1; + i=0; + while (size_rem > 0 && i < 7) { + int subsize=le32_to_cpu(*subpos++); + int subtype=le32_to_cpu(subpos[0]); + mr->attrs[i].type=subtype; + attr_data_set_le(&mr->attrs[i], subpos+1); + subpos+=subsize; + size_rem-=subsize+1; + i++; + } + mr->attrs[i].type=type_none; + mr->attrs[i].u.data=NULL; + attr->u.attrs=mr->attrs; + } else { + attr_data_set_le(attr, t->pos_attr+1); + if (type == attr_url_local) { + g_free(mr->url); + mr->url=binfile_extract(mr->m, mr->m->cachedir, attr->u.str, 1); + attr->u.str=mr->url; + } + if (type == attr_flags && mr->m->map_version < 1) + attr->u.num |= AF_CAR; + } + t->pos_attr+=size; + return 1; + } else { + t->pos_attr+=size; + } + } + if (!mr->label && (attr_type == attr_any || attr_type == attr_label)) { + for (i = 0 ; i < sizeof(mr->label_attr)/sizeof(int *) ; i++) { + if (mr->label_attr[i]) { + mr->label=1; + attr->type=attr_label; + attr_data_set_le(attr,mr->label_attr[i]+1); + return 1; + } + } + } + return 0; } struct binfile_hash_entry { - struct item_id id; - int flags; - int data[0]; + struct item_id id; + int flags; + int data[0]; }; -static guint -binfile_hash_entry_hash(gconstpointer key) -{ - const struct binfile_hash_entry *entry=key; - return (entry->id.id_hi ^ entry->id.id_lo); -} - -static gboolean -binfile_hash_entry_equal(gconstpointer a, gconstpointer b) -{ - const struct binfile_hash_entry *entry1=a,*entry2=b; - return (entry1->id.id_hi==entry2->id.id_hi && entry1->id.id_lo == entry2->id.id_lo); -} +static guint binfile_hash_entry_hash(gconstpointer key) { + const struct binfile_hash_entry *entry=key; + return (entry->id.id_hi ^ entry->id.id_lo); +} + +static gboolean binfile_hash_entry_equal(gconstpointer a, gconstpointer b) { + const struct binfile_hash_entry *entry1=a,*entry2=b; + return (entry1->id.id_hi==entry2->id.id_hi && entry1->id.id_lo == entry2->id.id_lo); +} + +static int *binfile_item_dup(struct map_priv *m, struct item *item, struct tile *t, int extend) { + int size=le32_to_cpu(t->pos[0]); + struct binfile_hash_entry *entry=g_malloc(sizeof(struct binfile_hash_entry)+(size+1+extend)*sizeof(int)); + void *ret=entry->data; + entry->id.id_hi=item->id_hi; + entry->id.id_lo=item->id_lo; + entry->flags=1; + dbg(lvl_debug,"id 0x%x,0x%x",entry->id.id_hi,entry->id.id_lo); + + memcpy(ret, t->pos, (size+1)*sizeof(int)); + if (!m->changes) + m->changes=g_hash_table_new_full(binfile_hash_entry_hash, binfile_hash_entry_equal, g_free, NULL); + g_hash_table_replace(m->changes, entry, entry); + dbg(lvl_debug,"ret %p",ret); + return ret; +} + +static int binfile_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode) { + struct map_rect_priv *mr=priv_data; + struct tile *t=mr->t,*tn,new; + int i,delta,move_len; + int write_offset,move_offset,aoffset,coffset,clen; + int *data; + + { + int *i=t->pos,j=0; + dbg(lvl_debug,"Before: pos_coord=%td",t->pos_coord-i); + while (i < t->pos_next) + dbg(lvl_debug,"%d:0x%x",j++,*i++); + + } + aoffset=t->pos_attr-t->pos_attr_start; + coffset=t->pos_coord-t->pos_coord_start-2; + clen=t->pos_attr_start-t->pos_coord+2; + dbg(lvl_debug,"coffset=%d clen=%d",coffset,clen); + switch (mode) { + case change_mode_delete: + if (count*2 > clen) + count=clen/2; + delta=-count*2; + move_offset=coffset+count*2; + move_len=t->pos_next-t->pos_coord_start-move_offset; + write_offset=0; + break; + case change_mode_modify: + write_offset=coffset; + if (count*2 > clen) { + delta=count*2-clen; + move_offset=t->pos_attr_start-t->pos_coord_start; + move_len=t->pos_next-t->pos_coord_start-move_offset; + } else { + move_len=0; + move_offset=0; + delta=0; + } + break; + case change_mode_prepend: + delta=count*2; + move_offset=coffset-2; + move_len=t->pos_next-t->pos_coord_start-move_offset; + write_offset=coffset-2; + break; + case change_mode_append: + delta=count*2; + move_offset=coffset; + move_len=t->pos_next-t->pos_coord_start-move_offset; + write_offset=coffset; + break; + default: + return 0; + } + dbg(lvl_debug,"delta %d",delta); + data=binfile_item_dup(mr->m, &mr->item, t, delta > 0 ? delta:0); + data[0]=cpu_to_le32(le32_to_cpu(data[0])+delta); + data[2]=cpu_to_le32(le32_to_cpu(data[2])+delta); + new.pos=new.start=data; + new.zipfile_num=t->zipfile_num; + new.mode=2; + push_tile(mr, &new, 0, 0); + setup_pos(mr); + tn=mr->t; + tn->pos_coord=tn->pos_coord_start+coffset; + tn->pos_attr=tn->pos_attr_start+aoffset; + dbg(lvl_debug,"moving %d ints from offset %td to %td",move_len,tn->pos_coord_start+move_offset-data, + tn->pos_coord_start+move_offset+delta-data); + memmove(tn->pos_coord_start+move_offset+delta, tn->pos_coord_start+move_offset, move_len*4); + { + int *i=tn->pos,j=0; + dbg(lvl_debug,"After move: pos_coord=%td",tn->pos_coord-i); + while (i < tn->pos_next) + dbg(lvl_debug,"%d:0x%x",j++,*i++); + } + if (mode != change_mode_append) + tn->pos_coord+=move_offset; + if (mode != change_mode_delete) { + dbg(lvl_debug,"writing %d ints at offset %td",count*2,write_offset+tn->pos_coord_start-data); + for (i = 0 ; i < count ; i++) { + tn->pos_coord_start[write_offset++]=c[i].x; + tn->pos_coord_start[write_offset++]=c[i].y; + } -static int * -binfile_item_dup(struct map_priv *m, struct item *item, struct tile *t, int extend) -{ - int size=le32_to_cpu(t->pos[0]); - struct binfile_hash_entry *entry=g_malloc(sizeof(struct binfile_hash_entry)+(size+1+extend)*sizeof(int)); - void *ret=entry->data; - entry->id.id_hi=item->id_hi; - entry->id.id_lo=item->id_lo; - entry->flags=1; - dbg(lvl_debug,"id 0x%x,0x%x\n",entry->id.id_hi,entry->id.id_lo); - - memcpy(ret, t->pos, (size+1)*sizeof(int)); - if (!m->changes) - m->changes=g_hash_table_new_full(binfile_hash_entry_hash, binfile_hash_entry_equal, g_free, NULL); - g_hash_table_replace(m->changes, entry, entry); - dbg(lvl_debug,"ret %p\n",ret); - return ret; -} - -static int -binfile_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode) -{ - struct map_rect_priv *mr=priv_data; - struct tile *t=mr->t,*tn,new; - int i,delta,move_len; - int write_offset,move_offset,aoffset,coffset,clen; - int *data; - - { - int *i=t->pos,j=0; - dbg(lvl_debug,"Before: pos_coord=%td\n",t->pos_coord-i); - while (i < t->pos_next) - dbg(lvl_debug,"%d:0x%x\n",j++,*i++); - - } - aoffset=t->pos_attr-t->pos_attr_start; - coffset=t->pos_coord-t->pos_coord_start-2; - clen=t->pos_attr_start-t->pos_coord+2; - dbg(lvl_debug,"coffset=%d clen=%d\n",coffset,clen); - switch (mode) { - case change_mode_delete: - if (count*2 > clen) - count=clen/2; - delta=-count*2; - move_offset=coffset+count*2; - move_len=t->pos_next-t->pos_coord_start-move_offset; - write_offset=0; - break; - case change_mode_modify: - write_offset=coffset; - if (count*2 > clen) { - delta=count*2-clen; - move_offset=t->pos_attr_start-t->pos_coord_start; - move_len=t->pos_next-t->pos_coord_start-move_offset; - } else { - move_len=0; - move_offset=0; - delta=0; - } - break; - case change_mode_prepend: - delta=count*2; - move_offset=coffset-2; - move_len=t->pos_next-t->pos_coord_start-move_offset; - write_offset=coffset-2; - break; - case change_mode_append: - delta=count*2; - move_offset=coffset; - move_len=t->pos_next-t->pos_coord_start-move_offset; - write_offset=coffset; - break; - default: - return 0; - } - dbg(lvl_debug,"delta %d\n",delta); - data=binfile_item_dup(mr->m, &mr->item, t, delta > 0 ? delta:0); - data[0]=cpu_to_le32(le32_to_cpu(data[0])+delta); - data[2]=cpu_to_le32(le32_to_cpu(data[2])+delta); - new.pos=new.start=data; - new.zipfile_num=t->zipfile_num; - new.mode=2; - push_tile(mr, &new, 0, 0); - setup_pos(mr); - tn=mr->t; - tn->pos_coord=tn->pos_coord_start+coffset; - tn->pos_attr=tn->pos_attr_start+aoffset; - dbg(lvl_debug,"moving %d ints from offset %td to %td\n",move_len,tn->pos_coord_start+move_offset-data,tn->pos_coord_start+move_offset+delta-data); - memmove(tn->pos_coord_start+move_offset+delta, tn->pos_coord_start+move_offset, move_len*4); - { - int *i=tn->pos,j=0; - dbg(lvl_debug,"After move: pos_coord=%td\n",tn->pos_coord-i); - while (i < tn->pos_next) - dbg(lvl_debug,"%d:0x%x\n",j++,*i++); - } - if (mode != change_mode_append) - tn->pos_coord+=move_offset; - if (mode != change_mode_delete) { - dbg(lvl_debug,"writing %d ints at offset %td\n",count*2,write_offset+tn->pos_coord_start-data); - for (i = 0 ; i < count ; i++) { - tn->pos_coord_start[write_offset++]=c[i].x; - tn->pos_coord_start[write_offset++]=c[i].y; - } - - } - { - int *i=tn->pos,j=0; - dbg(lvl_debug,"After: pos_coord=%td\n",tn->pos_coord-i); - while (i < tn->pos_next) - dbg(lvl_debug,"%d:0x%x\n",j++,*i++); - } - return 1; -} - -static int -binfile_attr_set(void *priv_data, struct attr *attr, enum change_mode mode) -{ - struct map_rect_priv *mr=priv_data; - struct tile *t=mr->t,*tn,new; - int offset,delta,move_len; - int write_offset,move_offset,naoffset,coffset,oattr_len; - int nattr_size,nattr_len,pad; - int *data; - - { - int *i=t->pos,j=0; - dbg(lvl_debug,"Before: pos_attr=%td\n",t->pos_attr-i); - while (i < t->pos_next) - dbg(lvl_debug,"%d:0x%x\n",j++,*i++); - - } - - write_offset=0; - naoffset=t->pos_attr-t->pos_attr_start; - coffset=t->pos_coord-t->pos_coord_start; - offset=0; - oattr_len=0; - if (!naoffset) { - if (mode == change_mode_delete || mode == change_mode_modify) { - dbg(lvl_error,"no attribute selected\n"); - return 0; - } - if (mode == change_mode_append) - naoffset=t->pos_next-t->pos_attr_start; - } - while (offset < naoffset) { - oattr_len=le32_to_cpu(t->pos_attr_start[offset])+1; - dbg(lvl_debug,"len %d\n",oattr_len); - write_offset=offset; - offset+=oattr_len; - } - move_len=t->pos_next-t->pos_attr_start-offset; - move_offset=offset; - switch (mode) { - case change_mode_delete: - nattr_size=0; - nattr_len=0; - pad=0; - break; - case change_mode_modify: - case change_mode_prepend: - case change_mode_append: - nattr_size=attr_data_size(attr); - pad=(4-(nattr_size%4))%4; - nattr_len=(nattr_size+pad)/4+2; - if (mode == change_mode_prepend) { - move_offset=write_offset; - move_len+=oattr_len; - } - if (mode == change_mode_append) { - write_offset=move_offset; - } - break; - default: - return 0; - } - if (mode == change_mode_delete || mode == change_mode_modify) - delta=nattr_len-oattr_len; - else - delta=nattr_len; - dbg(lvl_debug,"delta %d oattr_len %d nattr_len %d\n",delta,oattr_len, nattr_len); - data=binfile_item_dup(mr->m, &mr->item, t, delta > 0 ? delta:0); - data[0]=cpu_to_le32(le32_to_cpu(data[0])+delta); - new.pos=new.start=data; - new.zipfile_num=t->zipfile_num; - new.mode=2; - push_tile(mr, &new, 0, 0); - setup_pos(mr); - tn=mr->t; - tn->pos_coord=tn->pos_coord_start+coffset; - tn->pos_attr=tn->pos_attr_start+offset; - dbg(lvl_debug,"attr start %td offset %d\n",tn->pos_attr_start-data,offset); - dbg(lvl_debug,"moving %d ints from offset %td to %td\n",move_len,tn->pos_attr_start+move_offset-data,tn->pos_attr_start+move_offset+delta-data); - memmove(tn->pos_attr_start+move_offset+delta, tn->pos_attr_start+move_offset, move_len*4); - if (mode != change_mode_append) - tn->pos_attr+=delta; - { - int *i=tn->pos,j=0; - dbg(lvl_debug,"After move: pos_attr=%td\n",tn->pos_attr-i); - while (i < tn->pos_next) - dbg(lvl_debug,"%d:0x%x\n",j++,*i++); - } - if (nattr_len) { - int *nattr=tn->pos_attr_start+write_offset; - dbg(lvl_debug,"writing %d ints at %td\n",nattr_len,nattr-data); - nattr[0]=cpu_to_le32(nattr_len-1); - nattr[1]=cpu_to_le32(attr->type); - memcpy(nattr+2, attr_data_get(attr), nattr_size); - memset((unsigned char *)(nattr+2)+nattr_size, 0, pad); - } - { - int *i=tn->pos,j=0; - dbg(lvl_debug,"After: pos_attr=%td\n",tn->pos_attr-i); - while (i < tn->pos_next) - dbg(lvl_debug,"After: pos_attr=%td\n",tn->pos_attr-i); - while (i < tn->pos_next) - dbg(lvl_debug,"%d:0x%x\n",j++,*i++); - } - return 1; + } + { + int *i=tn->pos,j=0; + dbg(lvl_debug,"After: pos_coord=%td",tn->pos_coord-i); + while (i < tn->pos_next) + dbg(lvl_debug,"%d:0x%x",j++,*i++); + } + return 1; +} + +static int binfile_attr_set(void *priv_data, struct attr *attr, enum change_mode mode) { + struct map_rect_priv *mr=priv_data; + struct tile *t=mr->t,*tn,new; + int offset,delta,move_len; + int write_offset,move_offset,naoffset,coffset,oattr_len; + int nattr_size,nattr_len,pad; + int *data; + + { + int *i=t->pos,j=0; + dbg(lvl_debug,"Before: pos_attr=%td",t->pos_attr-i); + while (i < t->pos_next) + dbg(lvl_debug,"%d:0x%x",j++,*i++); + + } + + write_offset=0; + naoffset=t->pos_attr-t->pos_attr_start; + coffset=t->pos_coord-t->pos_coord_start; + offset=0; + oattr_len=0; + if (!naoffset) { + if (mode == change_mode_delete || mode == change_mode_modify) { + dbg(lvl_error,"no attribute selected"); + return 0; + } + if (mode == change_mode_append) + naoffset=t->pos_next-t->pos_attr_start; + } + while (offset < naoffset) { + oattr_len=le32_to_cpu(t->pos_attr_start[offset])+1; + dbg(lvl_debug,"len %d",oattr_len); + write_offset=offset; + offset+=oattr_len; + } + move_len=t->pos_next-t->pos_attr_start-offset; + move_offset=offset; + switch (mode) { + case change_mode_delete: + nattr_size=0; + nattr_len=0; + pad=0; + break; + case change_mode_modify: + case change_mode_prepend: + case change_mode_append: + nattr_size=attr_data_size(attr); + pad=(4-(nattr_size%4))%4; + nattr_len=(nattr_size+pad)/4+2; + if (mode == change_mode_prepend) { + move_offset=write_offset; + move_len+=oattr_len; + } + if (mode == change_mode_append) { + write_offset=move_offset; + } + break; + default: + return 0; + } + if (mode == change_mode_delete || mode == change_mode_modify) + delta=nattr_len-oattr_len; + else + delta=nattr_len; + dbg(lvl_debug,"delta %d oattr_len %d nattr_len %d",delta,oattr_len, nattr_len); + data=binfile_item_dup(mr->m, &mr->item, t, delta > 0 ? delta:0); + data[0]=cpu_to_le32(le32_to_cpu(data[0])+delta); + new.pos=new.start=data; + new.zipfile_num=t->zipfile_num; + new.mode=2; + push_tile(mr, &new, 0, 0); + setup_pos(mr); + tn=mr->t; + tn->pos_coord=tn->pos_coord_start+coffset; + tn->pos_attr=tn->pos_attr_start+offset; + dbg(lvl_debug,"attr start %td offset %d",tn->pos_attr_start-data,offset); + dbg(lvl_debug,"moving %d ints from offset %td to %td",move_len,tn->pos_attr_start+move_offset-data, + tn->pos_attr_start+move_offset+delta-data); + memmove(tn->pos_attr_start+move_offset+delta, tn->pos_attr_start+move_offset, move_len*4); + if (mode != change_mode_append) + tn->pos_attr+=delta; + { + int *i=tn->pos,j=0; + dbg(lvl_debug,"After move: pos_attr=%td",tn->pos_attr-i); + while (i < tn->pos_next) + dbg(lvl_debug,"%d:0x%x",j++,*i++); + } + if (nattr_len) { + int *nattr=tn->pos_attr_start+write_offset; + dbg(lvl_debug,"writing %d ints at %td",nattr_len,nattr-data); + nattr[0]=cpu_to_le32(nattr_len-1); + nattr[1]=cpu_to_le32(attr->type); + memcpy(nattr+2, attr_data_get(attr), nattr_size); + memset((unsigned char *)(nattr+2)+nattr_size, 0, pad); + } + { + int *i=tn->pos,j=0; + dbg(lvl_debug,"After: pos_attr=%td",tn->pos_attr-i); + while (i < tn->pos_next) + dbg(lvl_debug,"After: pos_attr=%td",tn->pos_attr-i); + while (i < tn->pos_next) + dbg(lvl_debug,"%d:0x%x",j++,*i++); + } + return 1; } static struct item_methods methods_binfile = { - binfile_coord_rewind, - binfile_coord_get, - binfile_attr_rewind, - binfile_attr_get, - NULL, - binfile_attr_set, - binfile_coord_set, + binfile_coord_rewind, + binfile_coord_get, + binfile_attr_rewind, + binfile_attr_get, + NULL, + binfile_attr_set, + binfile_coord_set, }; -static void -push_tile(struct map_rect_priv *mr, struct tile *t, int offset, int length) -{ - dbg_assert(mr->tile_depth < 8); - mr->t=&mr->tiles[mr->tile_depth++]; - *(mr->t)=*t; - mr->t->pos=mr->t->pos_next=mr->t->start+offset; - if (length == -1) - length=le32_to_cpu(mr->t->pos[0])+1; - if (length > 0) - mr->t->end=mr->t->pos+length; -} - -static int -pop_tile(struct map_rect_priv *mr) -{ - if (mr->tile_depth <= 1) - return 0; - if (mr->t->mode < 2) - file_data_free(mr->m->fi, (unsigned char *)(mr->t->start)); +static void push_tile(struct map_rect_priv *mr, struct tile *t, int offset, int length) { + dbg_assert(mr->tile_depth < 8); + mr->t=&mr->tiles[mr->tile_depth++]; + *(mr->t)=*t; + mr->t->pos=mr->t->pos_next=mr->t->start+offset; + if (length == -1) + length=le32_to_cpu(mr->t->pos[0])+1; + if (length > 0) + mr->t->end=mr->t->pos+length; +} + +static int pop_tile(struct map_rect_priv *mr) { + if (mr->tile_depth <= 1) + return 0; + if (mr->t->mode < 2) + file_data_free(mr->m->fi, (unsigned char *)(mr->t->start)); #ifdef DEBUG_SIZE #if DEBUG_SIZE > 0 - dbg(lvl_debug,"leave %d\n",mr->t->zipfile_num); + dbg(lvl_debug,"leave %d",mr->t->zipfile_num); #endif #endif - mr->t=&mr->tiles[--mr->tile_depth-1]; - return 1; -} - - -static int -zipfile_to_tile(struct map_priv *m, struct zip_cd *cd, struct tile *t) -{ - char buffer[1024]; - struct zip_lfh *lfh; - char *zipfn; - struct file *fi; - dbg(lvl_debug,"enter %p %p %p\n", m, cd, t); - dbg(lvl_debug,"cd->zipofst=0x"LONGLONG_HEX_FMT "\n", binfile_cd_offset(cd)); - t->start=NULL; - t->mode=1; - if (m->fis) - fi=m->fis[cd->zipdsk]; - else - fi=m->fi; - lfh=binfile_read_lfh(fi, binfile_cd_offset(cd)); - zipfn=(char *)(file_data_read(fi,binfile_cd_offset(cd)+sizeof(struct zip_lfh), lfh->zipfnln)); - strncpy(buffer, zipfn, lfh->zipfnln); - buffer[lfh->zipfnln]='\0'; - t->start=(int *)binfile_read_content(m, fi, binfile_cd_offset(cd), lfh); - t->end=t->start+lfh->zipuncmp/4; - t->fi=fi; - file_data_free(fi, (unsigned char *)zipfn); - file_data_free(fi, (unsigned char *)lfh); - return t->start != NULL; -} - - -static int -map_binfile_handle_redirect(struct map_priv *m) -{ - char *location=file_http_header(m->http, "location"); - if (!location) { - m->redirect=0; - return 0; - } - if (m->redirect) - return 0; - m->redirect=1; - dbg(lvl_debug,"redirected from %s to %s\n",m->url,location); - g_free(m->url); - m->url=g_strdup(location); - file_destroy(m->http); - m->http=NULL; - - return 1; -} - -static int -map_binfile_http_request(struct map_priv *m, struct attr **attrs) -{ - if (!m->http) { - m->http=file_create(NULL, attrs); - } else { - file_request(m->http, attrs); - } - return 1; -} - - -static long long -map_binfile_download_size(struct map_priv *m) -{ - struct attr url={attr_url}; - struct attr http_method={attr_http_method}; - struct attr persistent={attr_persistent}; - struct attr *attrs[4]; - int size_ret; - long long ret; - void *data; - - do { - attrs[0]=&url; - url.u.str=m->url; - attrs[1]=&http_method; - http_method.u.str="HEAD"; - persistent.u.num=1; - attrs[2]=&persistent; - attrs[3]=NULL; - - map_binfile_http_request(m, attrs); - data=file_data_read_special(m->http, 0, &size_ret); - g_free(data); - if (size_ret < 0) - return 0; - } while (map_binfile_handle_redirect(m)); - - ret=file_size(m->http); - dbg(lvl_debug,"file size "LONGLONG_FMT"\n",ret); - return ret; -} - - -static int -map_binfile_http_close(struct map_priv *m) -{ - if (m->http) { - file_destroy(m->http); - m->http=NULL; - } - return 1; -} - - -static struct file * -map_binfile_http_range(struct map_priv *m, long long offset, int size) -{ - struct attr *attrs[4]; - struct attr url={attr_url}; - struct attr http_header={attr_http_header}; - struct attr persistent={attr_persistent}; - - persistent.u.num=1; - attrs[0]=&url; - attrs[1]=&http_header; - attrs[2]=&persistent; - attrs[3]=NULL; - - url.u.str=m->url; - http_header.u.str=g_strdup_printf("Range: bytes="LONGLONG_FMT"-"LONGLONG_FMT,offset, offset+size-1); - map_binfile_http_request(m, attrs); - g_free(http_header.u.str); - return m->http; -} - -static unsigned char * -map_binfile_download_range(struct map_priv *m, long long offset, int size) -{ - unsigned char *ret; - int size_ret; - struct file *http=map_binfile_http_range(m, offset, size); - - ret=file_data_read_special(http, size, &size_ret); - if (size_ret != size) { - dbg(lvl_debug,"size %d vs %d\n",size,size_ret); - g_free(ret); - return NULL; - } - return ret; -} - -static struct zip_cd * -download_cd(struct map_download *download) -{ - struct map_priv *m=download->m; - struct zip64_eoc *zip64_eoc=(struct zip64_eoc *)file_data_read(m->fi, 0, sizeof(*zip64_eoc)); - struct zip_cd *cd=(struct zip_cd *)map_binfile_download_range(m, zip64_eoc->zip64eofst+download->zipfile*m->cde_size,m->cde_size); - file_data_free(m->fi, (unsigned char *)zip64_eoc); - dbg(lvl_debug,"needed cd, result %p\n",cd); - return cd; -} - -static int -download_request(struct map_download *download) -{ - struct attr url={attr_url}; - struct attr http_header={attr_http_header}; - struct attr persistent={attr_persistent}; - struct attr *attrs[4]; - - if(!download->m->download_enabled) - { - dbg(lvl_error,"Tried downloading while it's not allowed\n"); - return 0; - } - attrs[0]=&url; - persistent.u.num=1; - attrs[1]=&persistent; - attrs[2]=NULL; - if (strchr(download->m->url,'?')) { - url.u.str=g_strdup_printf("%smemberid=%d",download->m->url,download->zipfile); - download->dl_size=-1; - } else { - long long offset=binfile_cd_offset(download->cd_copy); - int size=download->cd_copy->zipcsiz+sizeof(struct zip_lfh)+download->cd_copy->zipcfnl; - url.u.str=g_strdup(download->m->url); - http_header.u.str=g_strdup_printf("Range: bytes="LONGLONG_FMT"-"LONGLONG_FMT,offset,offset+size-1); - attrs[2]=&http_header; - attrs[3]=NULL; - download->dl_size=size; - } - dbg(lvl_debug,"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); - map_binfile_http_request(download->m, attrs); - g_free(url.u.str); - download->http=download->m->http; - return 1; -} - - -static int -download_start(struct map_download *download) -{ - long long offset; - struct zip_eoc *eoc; - - if (!download->cd->zipcensig) { - download->cd_copy=download_cd(download); - } else { - download->cd_copy=g_malloc(download->m->cde_size); - memcpy(download->cd_copy, download->cd, download->m->cde_size); - } - file_data_remove(download->file, (unsigned char *)download->cd); - download->cd=NULL; - offset=file_size(download->file); - offset-=sizeof(struct zip_eoc); - eoc=(struct zip_eoc *)file_data_read(download->file, offset, sizeof(struct zip_eoc)); - download->zip_eoc=g_malloc(sizeof(struct zip_eoc)); - memcpy(download->zip_eoc, eoc, sizeof(struct zip_eoc)); - file_data_remove(download->file, (unsigned char *)eoc); - download->start_offset=download->offset=offset; - return download_request(download); -} - -static int -download_download(struct map_download *download) -{ - int size=64*1024,size_ret; - unsigned char *data; - if (download->dl_size != -1 && size > download->dl_size) - size=download->dl_size; - if (!size) - return 1; - data=file_data_read_special(download->http, size, &size_ret); - if (!download->read && download->m->http && map_binfile_handle_redirect(download->m)) { - g_free(data); - download_request(download); - return 0; - } - - dbg(lvl_debug,"got %d bytes writing at offset "LONGLONG_FMT"\n",size_ret,download->offset); - if (size_ret <= 0) { - g_free(data); - return 1; - } - file_data_write(download->file, download->offset, size_ret, data); - download->offset+=size_ret; - download->read+=size_ret; - download->dl_size-=size_ret; - if (download->dl_size != -1) - download->progress=download->read*100/(download->read+download->dl_size); - return 0; -} - -static int -download_finish(struct map_download *download) -{ - struct zip_lfh *lfh; - char *lfh_filename; - struct zip_cd_ext *ext; - long long lfh_offset; - file_data_write(download->file, download->offset, sizeof(struct zip_eoc), (void *)download->zip_eoc); - lfh=(struct zip_lfh *)(file_data_read(download->file,download->start_offset, sizeof(struct zip_lfh))); - ext=binfile_cd_ext(download->cd_copy); - if (ext) - ext->zipofst=download->start_offset; - else - download->cd_copy->zipofst=download->start_offset; - download->cd_copy->zipcsiz=lfh->zipsize; - download->cd_copy->zipcunc=lfh->zipuncmp; - download->cd_copy->zipccrc=lfh->zipcrc; - lfh_offset = binfile_cd_offset(download->cd_copy)+sizeof(struct zip_lfh); - lfh_filename=(char *)file_data_read(download->file,lfh_offset,lfh->zipfnln); - memcpy(download->cd_copy+1,lfh_filename,lfh->zipfnln); - file_data_remove(download->file,(void *)lfh_filename); - file_data_remove(download->file,(void *)lfh); - 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); - file_data_flush(download->file, download->m->eoc->zipeofst + download->zipfile*download->m->cde_size, sizeof(struct zip_cd)); - - g_free(download->cd_copy); - download->cd=(struct zip_cd *)(file_data_read(download->file, download->m->eoc->zipeofst + download->zipfile*download->m->cde_size, download->m->cde_size)); - cd_to_cpu(download->cd); - dbg(lvl_debug,"Offset %d\n",download->cd->zipofst); - return 1; -} - -static int -download_planet_size(struct map_download *download) -{ - download->size=map_binfile_download_size(download->m); - dbg(lvl_debug,"Planet size "LONGLONG_FMT"\n",download->size); - if (!download->size) - return 0; - return 1; -} - -static int -download_eoc(struct map_download *download) -{ - download->zip64_eoc=(struct zip64_eoc *)map_binfile_download_range(download->m, download->size-98, 98); - if (!download->zip64_eoc) - return 0; - download->zip64_eocl=(struct zip64_eocl *)(download->zip64_eoc+1); - download->zip_eoc=(struct zip_eoc *)(download->zip64_eocl+1); - if (download->zip64_eoc->zip64esig != zip64_eoc_sig || download->zip64_eocl->zip64lsig != zip64_eocl_sig || download->zip_eoc->zipesig != zip_eoc_sig) - { - dbg(lvl_error,"wrong signature on zip64_eoc downloaded from "LONGLONG_FMT"\n",download->size-98); - g_free(download->zip64_eoc); - return 0; - } - return 1; -} - -static int -download_directory_start(struct map_download *download) -{ - download->http=map_binfile_http_range(download->m, download->zip64_eoc->zip64eofst, download->zip64_eoc->zip64ecsz); - if (!download->http) - return 0; - return 1; + mr->t=&mr->tiles[--mr->tile_depth-1]; + return 1; +} + + +static int zipfile_to_tile(struct map_priv *m, struct zip_cd *cd, struct tile *t) { + char buffer[1024]; + struct zip_lfh *lfh; + char *zipfn; + struct file *fi; + dbg(lvl_debug,"enter %p %p %p", m, cd, t); + dbg(lvl_debug,"cd->zipofst=0x"LONGLONG_HEX_FMT "", binfile_cd_offset(cd)); + t->start=NULL; + t->mode=1; + if (m->fis) + fi=m->fis[cd->zipdsk]; + else + fi=m->fi; + lfh=binfile_read_lfh(fi, binfile_cd_offset(cd)); + zipfn=(char *)(file_data_read(fi,binfile_cd_offset(cd)+sizeof(struct zip_lfh), lfh->zipfnln)); + strncpy(buffer, zipfn, lfh->zipfnln); + buffer[lfh->zipfnln]='\0'; + t->start=(int *)binfile_read_content(m, fi, binfile_cd_offset(cd), lfh); + t->end=t->start+lfh->zipuncmp/4; + t->fi=fi; + file_data_free(fi, (unsigned char *)zipfn); + file_data_free(fi, (unsigned char *)lfh); + return t->start != NULL; +} + + +static int map_binfile_handle_redirect(struct map_priv *m) { + char *location=file_http_header(m->http, "location"); + if (!location) { + m->redirect=0; + return 0; + } + if (m->redirect) + return 0; + m->redirect=1; + dbg(lvl_debug,"redirected from %s to %s",m->url,location); + g_free(m->url); + m->url=g_strdup(location); + file_destroy(m->http); + m->http=NULL; + + return 1; +} + +static int map_binfile_http_request(struct map_priv *m, struct attr **attrs) { + if (!m->http) { + m->http=file_create(NULL, attrs); + } else { + file_request(m->http, attrs); + } + return 1; +} + + +static long long map_binfile_download_size(struct map_priv *m) { + struct attr url= {attr_url}; + struct attr http_method= {attr_http_method}; + struct attr persistent= {attr_persistent}; + struct attr *attrs[4]; + int size_ret; + long long ret; + void *data; + + do { + attrs[0]=&url; + url.u.str=m->url; + attrs[1]=&http_method; + http_method.u.str="HEAD"; + persistent.u.num=1; + attrs[2]=&persistent; + attrs[3]=NULL; + + map_binfile_http_request(m, attrs); + data=file_data_read_special(m->http, 0, &size_ret); + g_free(data); + if (size_ret < 0) + return 0; + } while (map_binfile_handle_redirect(m)); + + ret=file_size(m->http); + dbg(lvl_debug,"file size "LONGLONG_FMT"",ret); + return ret; +} + + +static int map_binfile_http_close(struct map_priv *m) { + if (m->http) { + file_destroy(m->http); + m->http=NULL; + } + return 1; +} + + +static struct file *map_binfile_http_range(struct map_priv *m, long long offset, int size) { + struct attr *attrs[4]; + struct attr url= {attr_url}; + struct attr http_header= {attr_http_header}; + struct attr persistent= {attr_persistent}; + + persistent.u.num=1; + attrs[0]=&url; + attrs[1]=&http_header; + attrs[2]=&persistent; + attrs[3]=NULL; + + url.u.str=m->url; + http_header.u.str=g_strdup_printf("Range: bytes="LONGLONG_FMT"-"LONGLONG_FMT,offset, offset+size-1); + map_binfile_http_request(m, attrs); + g_free(http_header.u.str); + return m->http; +} + +static unsigned char *map_binfile_download_range(struct map_priv *m, long long offset, int size) { + unsigned char *ret; + int size_ret; + struct file *http=map_binfile_http_range(m, offset, size); + + ret=file_data_read_special(http, size, &size_ret); + if (size_ret != size) { + dbg(lvl_debug,"size %d vs %d",size,size_ret); + g_free(ret); + return NULL; + } + return ret; +} + +static struct zip_cd *download_cd(struct map_download *download) { + struct map_priv *m=download->m; + struct zip64_eoc *zip64_eoc=(struct zip64_eoc *)file_data_read(m->fi, 0, sizeof(*zip64_eoc)); + struct zip_cd *cd=(struct zip_cd *)map_binfile_download_range(m, zip64_eoc->zip64eofst+download->zipfile*m->cde_size, + m->cde_size); + file_data_free(m->fi, (unsigned char *)zip64_eoc); + dbg(lvl_debug,"needed cd, result %p",cd); + return cd; +} + +static int download_request(struct map_download *download) { + struct attr url= {attr_url}; + struct attr http_header= {attr_http_header}; + struct attr persistent= {attr_persistent}; + struct attr *attrs[4]; + + if(!download->m->download_enabled) { + dbg(lvl_error,"Tried downloading while it's not allowed"); + return 0; + } + attrs[0]=&url; + persistent.u.num=1; + attrs[1]=&persistent; + attrs[2]=NULL; + if (strchr(download->m->url,'?')) { + url.u.str=g_strdup_printf("%smemberid=%d",download->m->url,download->zipfile); + download->dl_size=-1; + } else { + long long offset=binfile_cd_offset(download->cd_copy); + int size=download->cd_copy->zipcsiz+sizeof(struct zip_lfh)+download->cd_copy->zipcfnl; + url.u.str=g_strdup(download->m->url); + http_header.u.str=g_strdup_printf("Range: bytes="LONGLONG_FMT"-"LONGLONG_FMT,offset,offset+size-1); + attrs[2]=&http_header; + attrs[3]=NULL; + download->dl_size=size; + } + dbg(lvl_debug,"encountered missing tile %d %s(%s), Downloading %d bytes at "LONGLONG_FMT"",download->zipfile, url.u.str, + (char *)(download->cd_copy+1), download->dl_size, download->offset); + map_binfile_http_request(download->m, attrs); + g_free(url.u.str); + download->http=download->m->http; + return 1; +} + + +static int download_start(struct map_download *download) { + long long offset; + struct zip_eoc *eoc; + + if (!download->cd->zipcensig) { + download->cd_copy=download_cd(download); + } else { + download->cd_copy=g_malloc(download->m->cde_size); + memcpy(download->cd_copy, download->cd, download->m->cde_size); + } + file_data_remove(download->file, (unsigned char *)download->cd); + download->cd=NULL; + offset=file_size(download->file); + offset-=sizeof(struct zip_eoc); + eoc=(struct zip_eoc *)file_data_read(download->file, offset, sizeof(struct zip_eoc)); + download->zip_eoc=g_malloc(sizeof(struct zip_eoc)); + memcpy(download->zip_eoc, eoc, sizeof(struct zip_eoc)); + file_data_remove(download->file, (unsigned char *)eoc); + download->start_offset=download->offset=offset; + return download_request(download); +} + +static int download_download(struct map_download *download) { + int size=64*1024,size_ret; + unsigned char *data; + if (download->dl_size != -1 && size > download->dl_size) + size=download->dl_size; + if (!size) + return 1; + data=file_data_read_special(download->http, size, &size_ret); + if (!download->read && download->m->http && map_binfile_handle_redirect(download->m)) { + g_free(data); + download_request(download); + return 0; + } + + dbg(lvl_debug,"got %d bytes writing at offset "LONGLONG_FMT"",size_ret,download->offset); + if (size_ret <= 0) { + g_free(data); + return 1; + } + file_data_write(download->file, download->offset, size_ret, data); + download->offset+=size_ret; + download->read+=size_ret; + download->dl_size-=size_ret; + if (download->dl_size != -1) + download->progress=download->read*100/(download->read+download->dl_size); + return 0; +} + +static int download_finish(struct map_download *download) { + struct zip_lfh *lfh; + char *lfh_filename; + struct zip_cd_ext *ext; + long long lfh_offset; + file_data_write(download->file, download->offset, sizeof(struct zip_eoc), (void *)download->zip_eoc); + lfh=(struct zip_lfh *)(file_data_read(download->file,download->start_offset, sizeof(struct zip_lfh))); + ext=binfile_cd_ext(download->cd_copy); + if (ext) + ext->zipofst=download->start_offset; + else + download->cd_copy->zipofst=download->start_offset; + download->cd_copy->zipcsiz=lfh->zipsize; + download->cd_copy->zipcunc=lfh->zipuncmp; + download->cd_copy->zipccrc=lfh->zipcrc; + lfh_offset = binfile_cd_offset(download->cd_copy)+sizeof(struct zip_lfh); + lfh_filename=(char *)file_data_read(download->file,lfh_offset,lfh->zipfnln); + memcpy(download->cd_copy+1,lfh_filename,lfh->zipfnln); + file_data_remove(download->file,(void *)lfh_filename); + file_data_remove(download->file,(void *)lfh); + 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); + file_data_flush(download->file, download->m->eoc->zipeofst + download->zipfile*download->m->cde_size, + sizeof(struct zip_cd)); + + g_free(download->cd_copy); + download->cd=(struct zip_cd *)(file_data_read(download->file, + download->m->eoc->zipeofst + download->zipfile*download->m->cde_size, download->m->cde_size)); + cd_to_cpu(download->cd); + dbg(lvl_debug,"Offset %d",download->cd->zipofst); + return 1; +} + +static int download_planet_size(struct map_download *download) { + download->size=map_binfile_download_size(download->m); + dbg(lvl_debug,"Planet size "LONGLONG_FMT"",download->size); + if (!download->size) + return 0; + return 1; +} + +static int download_eoc(struct map_download *download) { + download->zip64_eoc=(struct zip64_eoc *)map_binfile_download_range(download->m, download->size-98, 98); + if (!download->zip64_eoc) + return 0; + download->zip64_eocl=(struct zip64_eocl *)(download->zip64_eoc+1); + download->zip_eoc=(struct zip_eoc *)(download->zip64_eocl+1); + if (download->zip64_eoc->zip64esig != zip64_eoc_sig || download->zip64_eocl->zip64lsig != zip64_eocl_sig + || download->zip_eoc->zipesig != zip_eoc_sig) { + dbg(lvl_error,"wrong signature on zip64_eoc downloaded from "LONGLONG_FMT"",download->size-98); + g_free(download->zip64_eoc); + return 0; + } + return 1; +} + +static int download_directory_start(struct map_download *download) { + download->http=map_binfile_http_range(download->m, download->zip64_eoc->zip64eofst, download->zip64_eoc->zip64ecsz); + if (!download->http) + return 0; + return 1; +} + +static int download_directory_do(struct map_download *download) { + int count; + + for (count = 0 ; count < 100 ; count++) { + int cd_xlen, size_ret; + unsigned char *cd_data; + struct zip_cd *cd; + cd=(struct zip_cd *)file_data_read_special(download->http, sizeof(*cd), &size_ret); + cd->zipcunc=0; + dbg(lvl_debug,"size_ret=%d",size_ret); + if (!size_ret) + return 0; + if (size_ret != sizeof(*cd) || cd->zipcensig != zip_cd_sig) { + dbg(lvl_error,"error1 size=%d vs %zu",size_ret, sizeof(*cd)); + return 0; + } + file_data_write(download->file, download->offset, sizeof(*cd), (unsigned char *)cd); + download->offset+=sizeof(*cd); + cd_xlen=cd->zipcfnl+cd->zipcxtl; + cd_data=file_data_read_special(download->http, cd_xlen, &size_ret); + if (size_ret != cd_xlen) { + dbg(lvl_error,"error2 size=%d vs %d",size_ret,cd_xlen); + return 0; + } + file_data_write(download->file, download->offset, cd_xlen, cd_data); + download->offset+=cd_xlen; + g_free(cd); + g_free(cd_data); + } + return 1; } -static int -download_directory_do(struct map_download *download) -{ - int count; - - for (count = 0 ; count < 100 ; count++) { - int cd_xlen, size_ret; - unsigned char *cd_data; - struct zip_cd *cd; - cd=(struct zip_cd *)file_data_read_special(download->http, sizeof(*cd), &size_ret); - cd->zipcunc=0; - dbg(lvl_debug,"size_ret=%d\n",size_ret); - if (!size_ret) - return 0; - if (size_ret != sizeof(*cd) || cd->zipcensig != zip_cd_sig) { - dbg(lvl_error,"error1 size=%d vs %zu\n",size_ret, sizeof(*cd)); - return 0; - } - file_data_write(download->file, download->offset, sizeof(*cd), (unsigned char *)cd); - download->offset+=sizeof(*cd); - cd_xlen=cd->zipcfnl+cd->zipcxtl; - cd_data=file_data_read_special(download->http, cd_xlen, &size_ret); - if (size_ret != cd_xlen) { - dbg(lvl_error,"error2 size=%d vs %d\n",size_ret,cd_xlen); - return 0; - } - file_data_write(download->file, download->offset, cd_xlen, cd_data); - download->offset+=cd_xlen; - g_free(cd); - g_free(cd_data); - } - return 1; -} - -static int -download_directory_finish(struct map_download *download) -{ - download->http=NULL; - return 1; +static int download_directory_finish(struct map_download *download) { + download->http=NULL; + return 1; } -static int -download_initial_finish(struct map_download *download) -{ - download->zip64_eoc->zip64eofst=download->cd1offset; - download->zip64_eocl->zip64lofst=download->offset; - download->zip_eoc->zipeofst=download->cd1offset; +static int download_initial_finish(struct map_download *download) { + download->zip64_eoc->zip64eofst=download->cd1offset; + download->zip64_eocl->zip64lofst=download->offset; + download->zip_eoc->zipeofst=download->cd1offset; #if 0 - file_data_write(download->file, download->offset, sizeof(*download->zip64_eoc), (unsigned char *)download->zip64_eoc); - download->offset+=sizeof(*download->zip64_eoc); - file_data_write(download->file, download->offset, sizeof(*download->zip64_eocl), (unsigned char *)download->zip64_eocl); - download->offset+=sizeof(*download->zip64_eocl); + file_data_write(download->file, download->offset, sizeof(*download->zip64_eoc), (unsigned char *)download->zip64_eoc); + download->offset+=sizeof(*download->zip64_eoc); + file_data_write(download->file, download->offset, sizeof(*download->zip64_eocl), (unsigned char *)download->zip64_eocl); + download->offset+=sizeof(*download->zip64_eocl); #endif - file_data_write(download->file, download->offset, sizeof(*download->zip_eoc), (unsigned char *)download->zip_eoc); - download->offset+=sizeof(*download->zip_eoc); - g_free(download->zip64_eoc); - download->zip64_eoc=NULL; - return 1; + file_data_write(download->file, download->offset, sizeof(*download->zip_eoc), (unsigned char *)download->zip_eoc); + download->offset+=sizeof(*download->zip_eoc); + g_free(download->zip64_eoc); + download->zip64_eoc=NULL; + return 1; } -static void -push_zipfile_tile_do(struct map_rect_priv *mr, struct zip_cd *cd, int zipfile, int offset, int length) +static void push_zipfile_tile_do(struct map_rect_priv *mr, struct zip_cd *cd, int zipfile, int offset, int length) { - struct tile t; - struct map_priv *m=mr->m; - struct file *f=m->fi; + struct tile t; + struct map_priv *m=mr->m; + struct file *f=m->fi; - dbg(lvl_debug,"enter %p %d\n", mr, zipfile); + dbg(lvl_debug,"enter %p %d", mr, zipfile); #ifdef DEBUG_SIZE #if DEBUG_SIZE > 0 - { - char filename[cd->zipcfnl+1]; - memcpy(filename, cd+1, cd->zipcfnl); - filename[cd->zipcfnl]='\0'; - dbg(lvl_debug,"enter %d (%s) %d\n",zipfile, filename, cd->zipcunc); - } + { + char filename[cd->zipcfnl+1]; + memcpy(filename, cd+1, cd->zipcfnl); + filename[cd->zipcfnl]='\0'; + dbg(lvl_debug,"enter %d (%s) %d",zipfile, filename, cd->zipcunc); + } #endif - mr->size+=cd->zipcunc; + mr->size+=cd->zipcunc; #endif - t.zipfile_num=zipfile; - if (zipfile_to_tile(m, cd, &t)) - push_tile(mr, &t, offset, length); - file_data_free(f, (unsigned char *)cd); -} - - -static struct zip_cd * -download(struct map_priv *m, struct map_rect_priv *mr, struct zip_cd *cd, int zipfile, int offset, int length, int async) -{ - struct map_download *download; - - if(!m->download_enabled) - return NULL; - - if (async == 2) { - download=m->download; - } else { - download=g_new0(struct map_download, 1); - if (mr) { - download->m=m; - download->mr=mr; - download->file=m->fi; - download->cd=cd; - download->zipfile=zipfile; - download->toffset=offset; - download->tlength=length; - download->state=1; - } else { - struct attr readwrite={attr_readwrite,{(void *)1}}; - struct attr create={attr_create,{(void *)1}}; - struct attr *attrs[3]; - attrs[0]=&readwrite; - attrs[1]=&create; - attrs[2]=NULL; - download->file=file_create(m->filename,attrs); - download->m=m; - download->state=4; - } - } - if (async == 1) { - m->download=download; - g_free(m->progress); - if (download->mr) - m->progress=g_strdup_printf("Download Tile %d 0%%",download->zipfile); - else - m->progress=g_strdup_printf("Download Map Information 0%%"); - callback_list_call_attr_0(m->cbl, attr_progress); - return NULL; - } - for (;;) { - dbg(lvl_debug,"state=%d\n",download->state); - switch (download->state) { - case 0: - dbg(lvl_error,"error\n"); - break; - case 1: - if (download_start(download)) - download->state=2; - else - download->state=0; - break; - case 2: - if (download_download(download)) - download->state=3; - else { - g_free(m->progress); - m->progress=g_strdup_printf("Download Tile %d %d%%",download->zipfile,download->progress); - callback_list_call_attr_0(m->cbl, attr_progress); - } - break; - case 3: - if (download_finish(download)) { - struct zip_cd *ret; - g_free(m->progress); - m->progress=g_strdup_printf("Download Tile %d 100%%",download->zipfile); - callback_list_call_attr_0(m->cbl, attr_progress); - if (async) { - push_zipfile_tile_do(download->mr, download->cd, download->zipfile, download->toffset, download->tlength); - ret=NULL; - } else - ret=download->cd; - g_free(m->progress); - m->progress=NULL; - g_free(download); - if (async) - m->download=NULL; - return ret; - } else - download->state=0; - break; - case 4: - if (download_planet_size(download)) - download->state=5; - else - download->state=0; - break; - case 5: - g_free(m->progress); - m->progress=g_strdup_printf("Download Map Information 50%%"); - callback_list_call_attr_0(m->cbl, attr_progress); - if (download_eoc(download)) - download->state=6; - else { - dbg(lvl_error,"download of eoc failed\n"); - download->state=0; - } - break; - case 6: - g_free(m->progress); - m->progress=g_strdup_printf("Download Map Information 100%%"); - callback_list_call_attr_0(m->cbl, attr_progress); - if (download_directory_start(download)) - download->state=7; - else - download->state=0; - break; - case 7: - g_free(m->progress); - m->progress=g_strdup_printf("Download Map Directory %d%%",(int)(download->offset*100/download->zip64_eoc->zip64ecsz)); - callback_list_call_attr_0(m->cbl, attr_progress); - if (!download_directory_do(download)) - download->state=8; - break; - case 8: - if (download_directory_finish(download)) - download->state=9; - else - download->state=0; - break; - case 9: - download_initial_finish(download); - m->fi=download->file; - g_free(m->progress); - m->progress=NULL; - g_free(download); - if (async) - m->download=NULL; - map_binfile_open(m); - break; - } - if (async) - return NULL; - } -} - -static int -push_zipfile_tile(struct map_rect_priv *mr, int zipfile, int offset, int length, int async) -{ - struct map_priv *m=mr->m; - struct file *f=m->fi; - long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst; - struct zip_cd *cd=(struct zip_cd *)(file_data_read(f, cdoffset + zipfile*m->cde_size, m->cde_size)); - dbg(lvl_debug,"read from "LONGLONG_FMT" %d bytes\n",cdoffset + zipfile*m->cde_size, m->cde_size); - cd_to_cpu(cd); - if (!cd->zipcunc && m->url) { - cd=download(m, mr, cd, zipfile, offset, length, async); - if (!cd) - return 1; - } - push_zipfile_tile_do(mr, cd, zipfile, offset, length); - return 0; -} - -static struct map_rect_priv * -map_rect_new_binfile_int(struct map_priv *map, struct map_selection *sel) -{ - struct map_rect_priv *mr; - - binfile_check_version(map); - dbg(lvl_debug,"map_rect_new_binfile\n"); - if (!map->fi && !map->url) - return NULL; - map_binfile_http_close(map); - mr=g_new0(struct map_rect_priv, 1); - mr->m=map; - mr->sel=sel; - mr->item.id_hi=0; - mr->item.id_lo=0; - mr->item.meth=&methods_binfile; - mr->item.priv_data=mr; - return mr; -} - -static void -tile_bbox(char *tile, int len, struct coord_rect *r) -{ - struct coord c; - int overlap=1; - int xo,yo; - struct coord_rect world_bbox = { - { WORLD_BOUNDINGBOX_MIN_X, WORLD_BOUNDINGBOX_MAX_Y}, /* left upper corner */ - { WORLD_BOUNDINGBOX_MAX_X, WORLD_BOUNDINGBOX_MIN_Y}, /* right lower corner */ - }; - *r=world_bbox; - while (len) { - c.x=(r->lu.x+r->rl.x)/2; - c.y=(r->lu.y+r->rl.y)/2; - xo=(r->rl.x-r->lu.x)*overlap/100; - yo=(r->lu.y-r->rl.y)*overlap/100; - switch (*tile) { - case 'a': - r->lu.x=c.x-xo; - r->rl.y=c.y-yo; - break; - case 'b': - r->rl.x=c.x+xo; - r->rl.y=c.y-yo; - break; - case 'c': - r->lu.x=c.x-xo; - r->lu.y=c.y+yo; - break; - case 'd': - r->rl.x=c.x+xo; - r->lu.y=c.y+yo; - break; - default: - return; - } - tile++; - len--; + t.zipfile_num=zipfile; + if (zipfile_to_tile(m, cd, &t)) + push_tile(mr, &t, offset, length); + file_data_free(f, (unsigned char *)cd); +} + + +static struct zip_cd *download(struct map_priv *m, struct map_rect_priv *mr, struct zip_cd *cd, int zipfile, int offset, + int length, + int async) { + struct map_download *download; + + if(!m->download_enabled) + return NULL; + + if (async == 2) { + download=m->download; + } else { + download=g_new0(struct map_download, 1); + if (mr) { + download->m=m; + download->mr=mr; + download->file=m->fi; + download->cd=cd; + download->zipfile=zipfile; + download->toffset=offset; + download->tlength=length; + download->state=1; + } else { + struct attr readwrite= {attr_readwrite,{(void *)1}}; + struct attr create= {attr_create,{(void *)1}}; + struct attr *attrs[3]; + attrs[0]=&readwrite; + attrs[1]=&create; + attrs[2]=NULL; + download->file=file_create(m->filename,attrs); + download->m=m; + download->state=4; } -} - -static int -map_download_selection_check(struct zip_cd *cd, struct map_selection *sel) -{ - struct coord_rect cd_rect; - if (cd->zipcunc) - return 0; - tile_bbox((char *)(cd+1), cd->zipcfnl, &cd_rect); - while (sel) { - if (coord_rect_overlap(&cd_rect, &sel->u.c_rect)) - return 1; - sel=sel->next; - } - return 0; -} - -static void -map_download_selection(struct map_priv *m, struct map_rect_priv *mr, struct map_selection *sel) -{ - int i; - struct zip_cd *cd; - for (i = 0 ; i < m->zip_members ; i++) { - cd=binfile_read_cd(m, m->cde_size*i, -1); - if (map_download_selection_check(cd, sel)) - download(m, mr, cd, i, 0, 0, 0); - file_data_free(m->fi, (unsigned char *)cd); - } -} - -static struct map_rect_priv * -map_rect_new_binfile(struct map_priv *map, struct map_selection *sel) -{ - struct map_rect_priv *mr=map_rect_new_binfile_int(map, sel); - struct tile t; - dbg(lvl_debug,"zip_members=%d\n", map->zip_members); - if (map->url && map->fi && sel && sel->order == 255) { - map_download_selection(map, mr, sel); - } - if (map->eoc) - mr->status=1; - else { - unsigned char *d; - if (map->fi) { - d=file_data_read(map->fi, 0, map->fi->size); - t.start=(int *)d; - t.end=(int *)(d+map->fi->size); - t.fi=map->fi; - t.zipfile_num=0; - t.mode=0; - push_tile(mr, &t, 0, 0); - } else if (map->url && !map->download) { - download(map, NULL, NULL, 0, 0, 0, 1); - mr->status=1; - } - } - return mr; -} - -static void -write_changes_do(gpointer key, gpointer value, gpointer user_data) -{ - struct binfile_hash_entry *entry=key; - FILE *out=user_data; - if (entry->flags) { - entry->flags=0; - fwrite(entry, sizeof(*entry)+(le32_to_cpu(entry->data[0])+1)*4, 1, out); - dbg(lvl_debug,"yes\n"); - } -} - -static void -write_changes(struct map_priv *m) -{ - FILE *changes; - char *changes_file; - if (!m->changes) - return; - changes_file=g_strdup_printf("%s.log",m->filename); - changes=fopen(changes_file,"ab"); - g_hash_table_foreach(m->changes, write_changes_do, changes); - fclose(changes); - g_free(changes_file); -} - -static void -load_changes(struct map_priv *m) -{ - FILE *changes; - char *changes_file; - struct binfile_hash_entry entry,*e; - int size; - changes_file=g_strdup_printf("%s.log",m->filename); - changes=fopen(changes_file,"rb"); - if (! changes) { - g_free(changes_file); - return; - } - m->changes=g_hash_table_new_full(binfile_hash_entry_hash, binfile_hash_entry_equal, g_free, NULL); - while (fread(&entry, sizeof(entry), 1, changes) == 1) { - if (fread(&size, sizeof(size), 1, changes) != 1) - break; - e=g_malloc(sizeof(struct binfile_hash_entry)+(le32_to_cpu(size)+1)*4); - *e=entry; - e->data[0]=size; - if (fread(e->data+1, le32_to_cpu(size)*4, 1, changes) != 1) - break; - g_hash_table_replace(m->changes, e, e); - } - fclose(changes); - g_free(changes_file); -} - - -static void -map_rect_destroy_binfile(struct map_rect_priv *mr) -{ - write_changes(mr->m); - while (pop_tile(mr)); + } + if (async == 1) { + m->download=download; + g_free(m->progress); + if (download->mr) + m->progress=g_strdup_printf("Download Tile %d 0%%",download->zipfile); + else + m->progress=g_strdup_printf("Download Map Information 0%%"); + callback_list_call_attr_0(m->cbl, attr_progress); + return NULL; + } + for (;;) { + dbg(lvl_debug,"state=%d",download->state); + switch (download->state) { + case 0: + dbg(lvl_error,"error"); + break; + case 1: + if (download_start(download)) + download->state=2; + else + download->state=0; + break; + case 2: + if (download_download(download)) + download->state=3; + else { + g_free(m->progress); + m->progress=g_strdup_printf("Download Tile %d %d%%",download->zipfile,download->progress); + callback_list_call_attr_0(m->cbl, attr_progress); + } + break; + case 3: + if (download_finish(download)) { + struct zip_cd *ret; + g_free(m->progress); + m->progress=g_strdup_printf("Download Tile %d 100%%",download->zipfile); + callback_list_call_attr_0(m->cbl, attr_progress); + if (async) { + push_zipfile_tile_do(download->mr, download->cd, download->zipfile, download->toffset, download->tlength); + ret=NULL; + } else + ret=download->cd; + g_free(m->progress); + m->progress=NULL; + g_free(download); + if (async) + m->download=NULL; + return ret; + } else + download->state=0; + break; + case 4: + if (download_planet_size(download)) + download->state=5; + else + download->state=0; + break; + case 5: + g_free(m->progress); + m->progress=g_strdup_printf("Download Map Information 50%%"); + callback_list_call_attr_0(m->cbl, attr_progress); + if (download_eoc(download)) + download->state=6; + else { + dbg(lvl_error,"download of eoc failed"); + download->state=0; + } + break; + case 6: + g_free(m->progress); + m->progress=g_strdup_printf("Download Map Information 100%%"); + callback_list_call_attr_0(m->cbl, attr_progress); + if (download_directory_start(download)) + download->state=7; + else + download->state=0; + break; + case 7: + g_free(m->progress); + m->progress=g_strdup_printf("Download Map Directory %d%%",(int)(download->offset*100/download->zip64_eoc->zip64ecsz)); + callback_list_call_attr_0(m->cbl, attr_progress); + if (!download_directory_do(download)) + download->state=8; + break; + case 8: + if (download_directory_finish(download)) + download->state=9; + else + download->state=0; + break; + case 9: + download_initial_finish(download); + m->fi=download->file; + g_free(m->progress); + m->progress=NULL; + g_free(download); + if (async) + m->download=NULL; + map_binfile_open(m); + break; + } + if (async) + return NULL; + } +} + +static int push_zipfile_tile(struct map_rect_priv *mr, int zipfile, int offset, int length, int async) { + struct map_priv *m=mr->m; + struct file *f=m->fi; + long long cdoffset=m->eoc64?m->eoc64->zip64eofst:m->eoc->zipeofst; + struct zip_cd *cd=(struct zip_cd *)(file_data_read(f, cdoffset + zipfile*m->cde_size, m->cde_size)); + dbg(lvl_debug,"read from "LONGLONG_FMT" %d bytes",cdoffset + zipfile*m->cde_size, m->cde_size); + cd_to_cpu(cd); + if (!cd->zipcunc && m->url) { + cd=download(m, mr, cd, zipfile, offset, length, async); + if (!cd) + return 1; + } + push_zipfile_tile_do(mr, cd, zipfile, offset, length); + return 0; +} + +static struct map_rect_priv *map_rect_new_binfile_int(struct map_priv *map, struct map_selection *sel) { + struct map_rect_priv *mr; + + binfile_check_version(map); + dbg(lvl_debug,"map_rect_new_binfile"); + if (!map->fi && !map->url) + return NULL; + map_binfile_http_close(map); + mr=g_new0(struct map_rect_priv, 1); + mr->m=map; + mr->sel=sel; + mr->item.id_hi=0; + mr->item.id_lo=0; + mr->item.meth=&methods_binfile; + mr->item.priv_data=mr; + return mr; +} + +static void tile_bbox(char *tile, int len, struct coord_rect *r) { + struct coord c; + int overlap=1; + int xo,yo; + struct coord_rect world_bbox = { + { WORLD_BOUNDINGBOX_MIN_X, WORLD_BOUNDINGBOX_MAX_Y}, /* left upper corner */ + { WORLD_BOUNDINGBOX_MAX_X, WORLD_BOUNDINGBOX_MIN_Y}, /* right lower corner */ + }; + *r=world_bbox; + while (len) { + c.x=(r->lu.x+r->rl.x)/2; + c.y=(r->lu.y+r->rl.y)/2; + xo=(r->rl.x-r->lu.x)*overlap/100; + yo=(r->lu.y-r->rl.y)*overlap/100; + switch (*tile) { + case 'a': + r->lu.x=c.x-xo; + r->rl.y=c.y-yo; + break; + case 'b': + r->rl.x=c.x+xo; + r->rl.y=c.y-yo; + break; + case 'c': + r->lu.x=c.x-xo; + r->lu.y=c.y+yo; + break; + case 'd': + r->rl.x=c.x+xo; + r->lu.y=c.y+yo; + break; + default: + return; + } + tile++; + len--; + } +} + +static int map_download_selection_check(struct zip_cd *cd, struct map_selection *sel) { + struct coord_rect cd_rect; + if (cd->zipcunc) + return 0; + tile_bbox((char *)(cd+1), cd->zipcfnl, &cd_rect); + while (sel) { + if (coord_rect_overlap(&cd_rect, &sel->u.c_rect)) + return 1; + sel=sel->next; + } + return 0; +} + +static void map_download_selection(struct map_priv *m, struct map_rect_priv *mr, struct map_selection *sel) { + int i; + struct zip_cd *cd; + for (i = 0 ; i < m->zip_members ; i++) { + cd=binfile_read_cd(m, m->cde_size*i, -1); + if (map_download_selection_check(cd, sel)) + download(m, mr, cd, i, 0, 0, 0); + file_data_free(m->fi, (unsigned char *)cd); + } +} + +static struct map_rect_priv *map_rect_new_binfile(struct map_priv *map, struct map_selection *sel) { + struct map_rect_priv *mr=map_rect_new_binfile_int(map, sel); + struct tile t; + dbg(lvl_debug,"zip_members=%d", map->zip_members); + if (map->url && map->fi && sel && sel->order == 255) { + map_download_selection(map, mr, sel); + } + if (map->eoc) + mr->status=1; + else { + unsigned char *d; + if (map->fi) { + d=file_data_read(map->fi, 0, map->fi->size); + t.start=(int *)d; + t.end=(int *)(d+map->fi->size); + t.fi=map->fi; + t.zipfile_num=0; + t.mode=0; + push_tile(mr, &t, 0, 0); + } else if (map->url && !map->download) { + download(map, NULL, NULL, 0, 0, 0, 1); + mr->status=1; + } + } + return mr; +} + +static void write_changes_do(gpointer key, gpointer value, gpointer user_data) { + struct binfile_hash_entry *entry=key; + FILE *out=user_data; + if (entry->flags) { + entry->flags=0; + fwrite(entry, sizeof(*entry)+(le32_to_cpu(entry->data[0])+1)*4, 1, out); + dbg(lvl_debug,"yes"); + } +} + +static void write_changes(struct map_priv *m) { + FILE *changes; + char *changes_file; + if (!m->changes) + return; + changes_file=g_strdup_printf("%s.log",m->filename); + changes=fopen(changes_file,"ab"); + g_hash_table_foreach(m->changes, write_changes_do, changes); + fclose(changes); + g_free(changes_file); +} + +static void load_changes(struct map_priv *m) { + FILE *changes; + char *changes_file; + struct binfile_hash_entry entry,*e; + int size; + changes_file=g_strdup_printf("%s.log",m->filename); + changes=fopen(changes_file,"rb"); + if (! changes) { + g_free(changes_file); + return; + } + m->changes=g_hash_table_new_full(binfile_hash_entry_hash, binfile_hash_entry_equal, g_free, NULL); + while (fread(&entry, sizeof(entry), 1, changes) == 1) { + if (fread(&size, sizeof(size), 1, changes) != 1) + break; + e=g_malloc(sizeof(struct binfile_hash_entry)+(le32_to_cpu(size)+1)*4); + *e=entry; + e->data[0]=size; + if (fread(e->data+1, le32_to_cpu(size)*4, 1, changes) != 1) + break; + g_hash_table_replace(m->changes, e, e); + } + fclose(changes); + g_free(changes_file); +} + + +static void map_rect_destroy_binfile(struct map_rect_priv *mr) { + write_changes(mr->m); + while (pop_tile(mr)); #ifdef DEBUG_SIZE - dbg(lvl_debug,"size=%d kb\n",mr->size/1024); + dbg(lvl_debug,"size=%d kb",mr->size/1024); #endif - if (mr->tiles[0].fi && mr->tiles[0].start) - file_data_free(mr->tiles[0].fi, (unsigned char *)(mr->tiles[0].start)); - g_free(mr->url); - map_binfile_http_close(mr->m); - g_free(mr); -} - -static void -setup_pos(struct map_rect_priv *mr) -{ - int size,coord_size; - struct tile *t=mr->t; - size=le32_to_cpu(t->pos[0]); - if (size > 1024*1024 || size < 0) { - dbg(lvl_debug,"size=0x%x\n", size); + if (mr->tiles[0].fi && mr->tiles[0].start) + file_data_free(mr->tiles[0].fi, (unsigned char *)(mr->tiles[0].start)); + g_free(mr->url); + map_binfile_http_close(mr->m); + g_free(mr); +} + +static void setup_pos(struct map_rect_priv *mr) { + int size,coord_size; + struct tile *t=mr->t; + size=le32_to_cpu(t->pos[0]); + if (size > 1024*1024 || size < 0) { + dbg(lvl_debug,"size=0x%x", size); #if 0 - fprintf(stderr,"offset=%d\n", (unsigned char *)(mr->pos)-mr->m->f->begin); -#endif - dbg(lvl_debug,"size error\n"); - } - t->pos_next=t->pos+size+1; - mr->item.type=le32_to_cpu(t->pos[1]); - coord_size=le32_to_cpu(t->pos[2]); - t->pos_coord_start=t->pos+3; - t->pos_attr_start=t->pos_coord_start+coord_size; -} - -static int -selection_contains(struct map_selection *sel, struct coord_rect *r, struct range *mima) -{ - int order; - if (! sel) - return 1; - while (sel) { - if (coord_rect_overlap(r, &sel->u.c_rect)) { - order=sel->order; - dbg(lvl_debug,"min %d max %d order %d\n", mima->min, mima->max, order); - if (!mima->min && !mima->max) - return 1; - if (order >= mima->min && order <= mima->max) - return 1; - } - sel=sel->next; - } - return 0; -} - -static void -map_parse_country_binfile(struct map_rect_priv *mr) -{ - struct attr at; - - if (!binfile_attr_get(mr->item.priv_data, attr_country_id, &at)) - return; - - if( at.u.num != mr->country_id) - return; - - if (!binfile_attr_get(mr->item.priv_data, attr_zipfile_ref, &at)) - return; - - if(mr->msp) - { - struct attr *search=&mr->msp->search; - if(search->type==attr_town_name || search->type==attr_district_name || search->type==attr_town_or_district_name) { - struct attr af, al; - if(binfile_attr_get(mr->item.priv_data, attr_first_key, &af)) { - if(linguistics_compare(af.u.str,search->u.str,linguistics_cmp_partial)>0) { - dbg(lvl_debug,"Skipping index item with first_key='%s'\n", af.u.str); - return; - } - } - if(binfile_attr_get(mr->item.priv_data, attr_last_key, &al)) { - if(linguistics_compare(al.u.str,search->u.str,linguistics_cmp_partial)<0) { - dbg(lvl_debug,"Skipping index item with first_key='%s', last_key='%s'\n", af.u.str, al.u.str); - return; - } - } - } - } - - push_zipfile_tile(mr, at.u.num, 0, 0, 0); -} - -static int -map_parse_submap(struct map_rect_priv *mr, int async) -{ - struct coord_rect r; - struct coord c[2]; - struct attr at; - struct range mima; - if (binfile_coord_get(mr->item.priv_data, c, 2) != 2) - return 0; - r.lu.x=c[0].x; - r.lu.y=c[1].y; - r.rl.x=c[1].x; - r.rl.y=c[0].y; - if (!binfile_attr_get(mr->item.priv_data, attr_order, &at)) - return 0; -#if __BYTE_ORDER == __BIG_ENDIAN - mima.min=le16_to_cpu(at.u.range.max); - mima.max=le16_to_cpu(at.u.range.min); -#else - mima=at.u.range; + fprintf(stderr,"offset=%d\n", (unsigned char *)(mr->pos)-mr->m->f->begin); #endif - if (!mr->m->eoc || !selection_contains(mr->sel, &r, &mima)) - return 0; - if (!binfile_attr_get(mr->item.priv_data, attr_zipfile_ref, &at)) - return 0; - dbg(lvl_debug,"pushing zipfile %ld from %d\n", at.u.num, mr->t->zipfile_num); - return push_zipfile_tile(mr, at.u.num, 0, 0, async); -} - -static int -push_modified_item(struct map_rect_priv *mr) -{ - struct item_id id; - struct binfile_hash_entry *entry; - id.id_hi=mr->item.id_hi; - id.id_lo=mr->item.id_lo; - entry=g_hash_table_lookup(mr->m->changes, &id); - if (entry) { - struct tile tn; - tn.pos_next=tn.pos=tn.start=entry->data; - tn.zipfile_num=mr->item.id_hi; - tn.mode=2; - tn.end=tn.start+le32_to_cpu(entry->data[0])+1; - push_tile(mr, &tn, 0, 0); - return 1; - } - return 0; -} - -static struct item * -map_rect_get_item_binfile(struct map_rect_priv *mr) -{ - struct tile *t; - struct map_priv *m=mr->m; - if (m->download) { - download(m, NULL, NULL, 0, 0, 0, 2); - return &busy_item; - } - if (mr->status == 1) { - mr->status=0; - if (push_zipfile_tile(mr, m->zip_members-1, 0, 0, 1)) - return &busy_item; - } - for (;;) { - t=mr->t; - if (! t) - return NULL; - t->pos=t->pos_next; - if (t->pos >= t->end) { - if (pop_tile(mr)) - continue; - return NULL; - } - setup_pos(mr); - binfile_coord_rewind(mr); - binfile_attr_rewind(mr); - if ((mr->item.type == type_submap) && (!mr->country_id)) { - if (map_parse_submap(mr, 1)) - return &busy_item; - continue; - } - if (t->mode != 2) { - mr->item.id_hi=t->zipfile_num; - mr->item.id_lo=t->pos-t->start; - if (mr->m->changes && push_modified_item(mr)) - continue; - } - if (mr->country_id) - { - if (mr->item.type == type_countryindex) { - map_parse_country_binfile(mr); - } - if (item_is_town(mr->item)) - { - return &mr->item; - } else { - continue; - } - } - return &mr->item; - } -} - -static struct item * -map_rect_get_item_byid_binfile(struct map_rect_priv *mr, int id_hi, int id_lo) -{ - struct tile *t; - if (mr->m->eoc) { - while (pop_tile(mr)); - push_zipfile_tile(mr, id_hi, 0, 0, 0); - } - t=mr->t; - t->pos=t->start+id_lo; - mr->item.id_hi=id_hi; - mr->item.id_lo=id_lo; - if (mr->m->changes) - push_modified_item(mr); - setup_pos(mr); - binfile_coord_rewind(mr); - binfile_attr_rewind(mr); - return &mr->item; -} - -static int -binmap_search_by_index(struct map_priv *map, struct item *item, struct map_rect_priv **ret) -{ - struct attr zipfile_ref; - int *data; - - if (!item) { - *ret=NULL; - return 0; - } - if (item_attr_get(item, attr_item_id, &zipfile_ref)) { - data=zipfile_ref.u.data; - *ret=map_rect_new_binfile_int(map, NULL); - push_zipfile_tile(*ret, le32_to_cpu(data[0]), le32_to_cpu(data[1]), -1, 0); - return 3; - } - if (item_attr_get(item, attr_zipfile_ref, &zipfile_ref)) { - *ret=map_rect_new_binfile_int(map, NULL); - push_zipfile_tile(*ret, zipfile_ref.u.num, 0, 0, 0); - return 1; - } - if (item_attr_get(item, attr_zipfile_ref_block, &zipfile_ref)) { - data=zipfile_ref.u.data; - *ret=map_rect_new_binfile_int(map, NULL); - push_zipfile_tile(*ret, le32_to_cpu(data[0]), le32_to_cpu(data[1]), le32_to_cpu(data[2]), 0); - return 2; - } - *ret=NULL; - return 0; -} - -static struct map_rect_priv * -binmap_search_street_by_place(struct map_priv *map, struct item *town, struct coord *c, struct map_selection *sel, GList **boundaries) -{ - struct attr town_name, poly_town_name; - struct map_rect_priv *map_rec2; - struct item *place; - int found=0; - - if (!item_attr_get(town, attr_label, &town_name)) - return NULL; - sel->range = item_range_all; - sel->order = 18; - sel->next = NULL; - sel->u.c_rect.lu=*c; - sel->u.c_rect.rl=*c; - map_rec2=map_rect_new_binfile(map, sel); - while ((place=map_rect_get_item_binfile(map_rec2))) { - if (item_is_poly_place(*place) && - item_attr_get(place, attr_label, &poly_town_name) && - !strcmp(poly_town_name.u.str,town_name.u.str)) { - struct coord *c; - int i,count; - struct geom_poly_segment *bnd; - count=binfile_coord_left(map_rec2); - c=g_new(struct coord,count); - found=1; - item_coord_get(place, c, count); - for (i = 0 ; i < count ; i++) - coord_rect_extend(&sel->u.c_rect, &c[i]); - bnd=g_new(struct geom_poly_segment,1); - bnd->first=c; - bnd->last=c+count-1; - bnd->type=geom_poly_segment_type_way_outer; - *boundaries=g_list_prepend(*boundaries,bnd); - } - } - map_rect_destroy_binfile(map_rec2); - if (found) - return map_rect_new_binfile(map, sel); - return NULL; -} - -static int -binmap_get_estimated_town_size(struct item *town) -{ - int size = 10000; - switch (town->type) { - case type_town_label_1e5: - case type_town_label_5e4: - case type_town_label_2e4: - case type_district_label_1e5: - case type_district_label_5e4: - case type_district_label_2e4: - size = 5000; - break; - case type_town_label_1e4: - case type_town_label_5e3: - case type_town_label_2e3: - case type_district_label_1e4: - case type_district_label_5e3: - case type_district_label_2e3: - size = 2500; - break; - case type_town_label_1e3: - case type_town_label_5e2: - case type_town_label_2e2: - case type_town_label_1e2: - case type_town_label_5e1: - case type_town_label_2e1: - case type_town_label_1e1: - case type_town_label_5e0: - case type_town_label_2e0: - case type_town_label_1e0: - case type_town_label_0e0: - case type_district_label_1e3: - case type_district_label_5e2: - case type_district_label_2e2: - case type_district_label_1e2: - case type_district_label_5e1: - case type_district_label_2e1: - case type_district_label_1e1: - case type_district_label_5e0: - case type_district_label_2e0: - case type_district_label_1e0: - case type_district_label_0e0: - size = 1000; - break; - default: - break; - } - return size; -} - -static struct map_rect_priv * -binmap_search_street_by_estimate(struct map_priv *map, struct item *town, struct coord *c, struct map_selection *sel) -{ - int size = binmap_get_estimated_town_size(town); - - sel->u.c_rect.lu.x = c->x-size; - sel->u.c_rect.lu.y = c->y+size; - sel->u.c_rect.rl.x = c->x+size; - sel->u.c_rect.rl.y = c->y-size; - return map_rect_new_binfile(map, sel); + dbg(lvl_debug,"size error"); + } + t->pos_next=t->pos+size+1; + mr->item.type=le32_to_cpu(t->pos[1]); + coord_size=le32_to_cpu(t->pos[2]); + t->pos_coord_start=t->pos+3; + t->pos_attr_start=t->pos_coord_start+coord_size; +} + +static int selection_contains(struct map_selection *sel, struct coord_rect *r, struct range *mima) { + int order; + if (! sel) + return 1; + while (sel) { + if (coord_rect_overlap(r, &sel->u.c_rect)) { + order=sel->order; + dbg(lvl_debug,"min %d max %d order %d", mima->min, mima->max, order); + if (!mima->min && !mima->max) + return 1; + if (order >= mima->min && order <= mima->max) + return 1; + } + sel=sel->next; + } + return 0; } -static struct map_rect_priv * -binmap_search_housenumber_by_estimate(struct map_priv *map, struct coord *c, struct map_selection *sel) -{ - int size = 400; - sel->u.c_rect.lu.x = c->x-size; - sel->u.c_rect.lu.y = c->y+size; - sel->u.c_rect.rl.x = c->x+size; - sel->u.c_rect.rl.y = c->y-size; - - sel->range = item_range_all; - sel->order = 18; +static void map_parse_country_binfile(struct map_rect_priv *mr) { + struct attr at; - return map_rect_new_binfile(map, sel); -} + if (!binfile_attr_get(mr->item.priv_data, attr_country_id, &at)) + return; + if( at.u.num != mr->country_id) + return; -static int -binmap_get_estimated_boundaries (struct item *town, GList **boundaries) -{ - int size = binmap_get_estimated_town_size(town); - struct coord tc; - - if (item_coord_get(town, &tc, 1)) - { - struct geom_poly_segment *bnd; - struct coord *c; - c=g_new(struct coord,5); - bnd=g_new(struct geom_poly_segment,1); - c[0].x = tc.x + size; - c[0].y = tc.y - size; - c[1].x = tc.x - size; - c[1].y = tc.y - size; - c[2].x = tc.x - size; - c[2].y = tc.y + size; - c[3].x = tc.x + size; - c[3].y = tc.y + size; - c[4].x = c[0].x; - c[4].y = c[0].y; - bnd->first=&c[0]; - bnd->last=&c[4]; - bnd->type=geom_poly_segment_type_way_outer; - *boundaries=g_list_prepend(*boundaries,bnd); - return 1; - } - return 0; -} - -static struct map_search_priv * -binmap_search_new(struct map_priv *map, struct item *item, struct attr *search, int partial) -{ - struct map_rect_priv *map_rec; - struct map_search_priv *msp=g_new0(struct map_search_priv, 1); - struct item *town; - int idx; - - msp->search = *search; - msp->partial = partial; - if(ATTR_IS_STRING(msp->search.type)) - msp->search.u.str=linguistics_casefold(search->u.str); + if (!binfile_attr_get(mr->item.priv_data, attr_zipfile_ref, &at)) + return; - /* + if(mr->msp) { + struct attr *search=&mr->msp->search; + if(search->type==attr_town_name || search->type==attr_district_name || search->type==attr_town_or_district_name) { + struct attr af, al; + if(binfile_attr_get(mr->item.priv_data, attr_first_key, &af)) { + if(linguistics_compare(af.u.str,search->u.str,linguistics_cmp_partial)>0) { + dbg(lvl_debug,"Skipping index item with first_key='%s'", af.u.str); + return; + } + } + if(binfile_attr_get(mr->item.priv_data, attr_last_key, &al)) { + if(linguistics_compare(al.u.str,search->u.str,linguistics_cmp_partial)<0) { + dbg(lvl_debug,"Skipping index item with first_key='%s', last_key='%s'", af.u.str, al.u.str); + return; + } + } + } + } + + push_zipfile_tile(mr, at.u.num, 0, 0, 0); +} + +static int map_parse_submap(struct map_rect_priv *mr, int async) { + struct coord_rect r; + struct coord c[2]; + struct attr at; + struct range mima; + if (binfile_coord_get(mr->item.priv_data, c, 2) != 2) + return 0; + r.lu.x=c[0].x; + r.lu.y=c[1].y; + r.rl.x=c[1].x; + r.rl.y=c[0].y; + if (!binfile_attr_get(mr->item.priv_data, attr_order, &at)) + return 0; +#if __BYTE_ORDER == __BIG_ENDIAN + mima.min=le16_to_cpu(at.u.range.max); + mima.max=le16_to_cpu(at.u.range.min); +#else + mima=at.u.range; +#endif + if (!mr->m->eoc || !selection_contains(mr->sel, &r, &mima)) + return 0; + if (!binfile_attr_get(mr->item.priv_data, attr_zipfile_ref, &at)) + return 0; + dbg(lvl_debug,"pushing zipfile %ld from %d", at.u.num, mr->t->zipfile_num); + return push_zipfile_tile(mr, at.u.num, 0, 0, async); +} + +static int push_modified_item(struct map_rect_priv *mr) { + struct item_id id; + struct binfile_hash_entry *entry; + id.id_hi=mr->item.id_hi; + id.id_lo=mr->item.id_lo; + entry=g_hash_table_lookup(mr->m->changes, &id); + if (entry) { + struct tile tn; + tn.pos_next=tn.pos=tn.start=entry->data; + tn.zipfile_num=mr->item.id_hi; + tn.mode=2; + tn.end=tn.start+le32_to_cpu(entry->data[0])+1; + push_tile(mr, &tn, 0, 0); + return 1; + } + return 0; +} + +static struct item *map_rect_get_item_binfile(struct map_rect_priv *mr) { + struct tile *t; + struct map_priv *m=mr->m; + if (m->download) { + download(m, NULL, NULL, 0, 0, 0, 2); + return &busy_item; + } + if (mr->status == 1) { + mr->status=0; + if (push_zipfile_tile(mr, m->zip_members-1, 0, 0, 1)) + return &busy_item; + } + for (;;) { + t=mr->t; + if (! t) + return NULL; + t->pos=t->pos_next; + if (t->pos >= t->end) { + if (pop_tile(mr)) + continue; + return NULL; + } + setup_pos(mr); + binfile_coord_rewind(mr); + binfile_attr_rewind(mr); + if ((mr->item.type == type_submap) && (!mr->country_id)) { + if (map_parse_submap(mr, 1)) + return &busy_item; + continue; + } + if (t->mode != 2) { + mr->item.id_hi=t->zipfile_num; + mr->item.id_lo=t->pos-t->start; + if (mr->m->changes && push_modified_item(mr)) + continue; + } + if (mr->country_id) { + if (mr->item.type == type_countryindex) { + map_parse_country_binfile(mr); + } + if (item_is_town(mr->item)) { + return &mr->item; + } else { + continue; + } + } + return &mr->item; + } +} + +static struct item *map_rect_get_item_byid_binfile(struct map_rect_priv *mr, int id_hi, int id_lo) { + struct tile *t; + if (mr->m->eoc) { + while (pop_tile(mr)); + push_zipfile_tile(mr, id_hi, 0, 0, 0); + } + t=mr->t; + t->pos=t->start+id_lo; + mr->item.id_hi=id_hi; + mr->item.id_lo=id_lo; + if (mr->m->changes) + push_modified_item(mr); + setup_pos(mr); + binfile_coord_rewind(mr); + binfile_attr_rewind(mr); + return &mr->item; +} + +static int binmap_search_by_index(struct map_priv *map, struct item *item, struct map_rect_priv **ret) { + struct attr zipfile_ref; + int *data; + + if (!item) { + *ret=NULL; + return 0; + } + if (item_attr_get(item, attr_item_id, &zipfile_ref)) { + data=zipfile_ref.u.data; + *ret=map_rect_new_binfile_int(map, NULL); + push_zipfile_tile(*ret, le32_to_cpu(data[0]), le32_to_cpu(data[1]), -1, 0); + return 3; + } + if (item_attr_get(item, attr_zipfile_ref, &zipfile_ref)) { + *ret=map_rect_new_binfile_int(map, NULL); + push_zipfile_tile(*ret, zipfile_ref.u.num, 0, 0, 0); + return 1; + } + if (item_attr_get(item, attr_zipfile_ref_block, &zipfile_ref)) { + data=zipfile_ref.u.data; + *ret=map_rect_new_binfile_int(map, NULL); + push_zipfile_tile(*ret, le32_to_cpu(data[0]), le32_to_cpu(data[1]), le32_to_cpu(data[2]), 0); + return 2; + } + *ret=NULL; + return 0; +} + +static struct map_rect_priv *binmap_search_street_by_place(struct map_priv *map, struct item *town, struct coord *c, + struct map_selection *sel, + GList **boundaries) { + struct attr town_name, poly_town_name; + struct map_rect_priv *map_rec2; + struct item *place; + int found=0; + + if (!item_attr_get(town, attr_label, &town_name)) + return NULL; + sel->range = item_range_all; + sel->order = 18; + sel->next = NULL; + sel->u.c_rect.lu=*c; + sel->u.c_rect.rl=*c; + map_rec2=map_rect_new_binfile(map, sel); + while ((place=map_rect_get_item_binfile(map_rec2))) { + if (item_is_poly_place(*place) && + item_attr_get(place, attr_label, &poly_town_name) && + !strcmp(poly_town_name.u.str,town_name.u.str)) { + struct coord *c; + int i,count; + struct geom_poly_segment *bnd; + count=binfile_coord_left(map_rec2); + c=g_new(struct coord,count); + found=1; + item_coord_get(place, c, count); + for (i = 0 ; i < count ; i++) + coord_rect_extend(&sel->u.c_rect, &c[i]); + bnd=g_new(struct geom_poly_segment,1); + bnd->first=c; + bnd->last=c+count-1; + bnd->type=geom_poly_segment_type_way_outer; + *boundaries=g_list_prepend(*boundaries,bnd); + } + } + map_rect_destroy_binfile(map_rec2); + if (found) + return map_rect_new_binfile(map, sel); + return NULL; +} + +static int binmap_get_estimated_town_size(struct item *town) { + int size = 10000; + switch (town->type) { + case type_town_label_1e5: + case type_town_label_5e4: + case type_town_label_2e4: + case type_district_label_1e5: + case type_district_label_5e4: + case type_district_label_2e4: + size = 5000; + break; + case type_town_label_1e4: + case type_town_label_5e3: + case type_town_label_2e3: + case type_district_label_1e4: + case type_district_label_5e3: + case type_district_label_2e3: + size = 2500; + break; + case type_town_label_1e3: + case type_town_label_5e2: + case type_town_label_2e2: + case type_town_label_1e2: + case type_town_label_5e1: + case type_town_label_2e1: + case type_town_label_1e1: + case type_town_label_5e0: + case type_town_label_2e0: + case type_town_label_1e0: + case type_town_label_0e0: + case type_district_label_1e3: + case type_district_label_5e2: + case type_district_label_2e2: + case type_district_label_1e2: + case type_district_label_5e1: + case type_district_label_2e1: + case type_district_label_1e1: + case type_district_label_5e0: + case type_district_label_2e0: + case type_district_label_1e0: + case type_district_label_0e0: + size = 1000; + break; + default: + break; + } + return size; +} + +static struct map_rect_priv *binmap_search_street_by_estimate(struct map_priv *map, struct item *town, struct coord *c, + struct map_selection *sel) { + int size = binmap_get_estimated_town_size(town); + + sel->u.c_rect.lu.x = c->x-size; + sel->u.c_rect.lu.y = c->y+size; + sel->u.c_rect.rl.x = c->x+size; + sel->u.c_rect.rl.y = c->y-size; + return map_rect_new_binfile(map, sel); +} + +static struct map_rect_priv *binmap_search_housenumber_by_estimate(struct map_priv *map, struct coord *c, + struct map_selection *sel) { + int size = 400; + sel->u.c_rect.lu.x = c->x-size; + sel->u.c_rect.lu.y = c->y+size; + sel->u.c_rect.rl.x = c->x+size; + sel->u.c_rect.rl.y = c->y-size; + + sel->range = item_range_all; + sel->order = 18; + + return map_rect_new_binfile(map, sel); +} + + +static int binmap_get_estimated_boundaries (struct item *town, GList **boundaries) { + int size = binmap_get_estimated_town_size(town); + struct coord tc; + + if (item_coord_get(town, &tc, 1)) { + struct geom_poly_segment *bnd; + struct coord *c; + c=g_new(struct coord,5); + bnd=g_new(struct geom_poly_segment,1); + c[0].x = tc.x + size; + c[0].y = tc.y - size; + c[1].x = tc.x - size; + c[1].y = tc.y - size; + c[2].x = tc.x - size; + c[2].y = tc.y + size; + c[3].x = tc.x + size; + c[3].y = tc.y + size; + c[4].x = c[0].x; + c[4].y = c[0].y; + bnd->first=&c[0]; + bnd->last=&c[4]; + bnd->type=geom_poly_segment_type_way_outer; + *boundaries=g_list_prepend(*boundaries,bnd); + return 1; + } + return 0; +} + +static struct map_search_priv *binmap_search_new(struct map_priv *map, struct item *item, struct attr *search, + int partial) { + struct map_rect_priv *map_rec; + struct map_search_priv *msp=g_new0(struct map_search_priv, 1); + struct item *town; + int idx; + + msp->search = *search; + msp->partial = partial; + if(ATTR_IS_STRING(msp->search.type)) + msp->search.u.str=linguistics_casefold(search->u.str); + + /* * NOTE: If you implement search for other attributes than attr_town_name and attr_street_name, * please update this comment and the documentation for map_search_new() in map.c */ - switch (search->type) { - case attr_country_name: - break; - case attr_town_name: - case attr_town_or_district_name: - case attr_town_postal: - map_rec = map_rect_new_binfile(map, NULL); - if (!map_rec) - break; - map_rec->country_id = item->id_lo; - map_rec->msp = msp; - msp->mr = map_rec; - return msp; - break; - case attr_street_name: - if (! item->map) - break; - if (!map_priv_is(item->map, map)) - break; - map_rec = map_rect_new_binfile(map, NULL); - town = map_rect_get_item_byid_binfile(map_rec, item->id_hi, item->id_lo); - if (town) { - struct coord c; - - if (binmap_search_by_index(map, town, &msp->mr)) - msp->mode = 1; - else { - map->last_searched_town_id_hi = town->id_hi; - map->last_searched_town_id_lo = town->id_lo; - if (item_coord_get(town, &c, 1)) { - if ((msp->mr=binmap_search_street_by_place(map, town, &c, &msp->ms, &msp->boundaries))) - msp->mode = 2; - else { - msp->mr=binmap_search_street_by_estimate(map, town, &c, &msp->ms); - msp->mode = 3; - } - } - } - map_rect_destroy_binfile(map_rec); - if (!msp->mr) - break; - return msp; - } - map_rect_destroy_binfile(map_rec); - break; - case attr_house_number: - dbg(lvl_debug,"case house_number"); - if (! item->map) - break; - if (!map_priv_is(item->map, map)) - break; - msp->map=map; - msp->mr_item = map_rect_new_binfile(map, NULL); - msp->item = map_rect_get_item_byid_binfile(msp->mr_item, item->id_hi, item->id_lo); - idx=binmap_search_by_index(map, msp->item, &msp->mr); - if (idx) - msp->mode = 1; - else - { - struct coord c; - if (item_coord_get(msp->item, &c, 1)) - { - struct attr attr; - map_rec = map_rect_new_binfile(map, NULL); - town = map_rect_get_item_byid_binfile(map_rec, map->last_searched_town_id_hi, map->last_searched_town_id_lo); - if (town) - msp->mr = binmap_search_street_by_place(map, town, &c, &msp->ms, &msp->boundaries); - if (msp->boundaries) - dbg(lvl_debug, "using map town boundaries\n"); - if (!msp->boundaries && town) - { - binmap_get_estimated_boundaries(town, &msp->boundaries); - if (msp->boundaries) - dbg(lvl_debug, "using estimated boundaries\n"); - } - map_rect_destroy_binfile(map_rec); - /* start searching in area around the street segment even if town boundaries are available */ - msp->mr=binmap_search_housenumber_by_estimate(map, &c, &msp->ms); - msp->mode = 2; - msp->rect_new=msp->ms.u.c_rect; - if(item_attr_get(msp->item, attr_street_name, &attr)) - msp->parent_name=g_strdup(attr.u.str); - dbg(lvl_debug,"pn=%s\n",msp->parent_name); - } - } - if (idx != 3) { - map_rect_destroy_binfile(msp->mr_item); - msp->mr_item=NULL; - } - if (!msp->mr) - { - break; - } - return msp; - default: - break; - } - if(ATTR_IS_STRING(msp->search.type)) - g_free(msp->search.u.str); - g_free(msp); - return NULL; -} - - -struct duplicate -{ - struct coord c; - char str[0]; + switch (search->type) { + case attr_country_name: + break; + case attr_town_name: + case attr_town_or_district_name: + case attr_town_postal: + map_rec = map_rect_new_binfile(map, NULL); + if (!map_rec) + break; + map_rec->country_id = item->id_lo; + map_rec->msp = msp; + msp->mr = map_rec; + return msp; + break; + case attr_street_name: + if (! item->map) + break; + if (!map_priv_is(item->map, map)) + break; + map_rec = map_rect_new_binfile(map, NULL); + town = map_rect_get_item_byid_binfile(map_rec, item->id_hi, item->id_lo); + if (town) { + struct coord c; + + if (binmap_search_by_index(map, town, &msp->mr)) + msp->mode = 1; + else { + map->last_searched_town_id_hi = town->id_hi; + map->last_searched_town_id_lo = town->id_lo; + if (item_coord_get(town, &c, 1)) { + if ((msp->mr=binmap_search_street_by_place(map, town, &c, &msp->ms, &msp->boundaries))) + msp->mode = 2; + else { + msp->mr=binmap_search_street_by_estimate(map, town, &c, &msp->ms); + msp->mode = 3; + } + } + } + map_rect_destroy_binfile(map_rec); + if (!msp->mr) + break; + return msp; + } + map_rect_destroy_binfile(map_rec); + break; + case attr_house_number: + dbg(lvl_debug,"case house_number"); + if (! item->map) + break; + if (!map_priv_is(item->map, map)) + break; + msp->map=map; + msp->mr_item = map_rect_new_binfile(map, NULL); + msp->item = map_rect_get_item_byid_binfile(msp->mr_item, item->id_hi, item->id_lo); + idx=binmap_search_by_index(map, msp->item, &msp->mr); + if (idx) + msp->mode = 1; + else { + struct coord c; + if (item_coord_get(msp->item, &c, 1)) { + struct attr attr; + map_rec = map_rect_new_binfile(map, NULL); + town = map_rect_get_item_byid_binfile(map_rec, map->last_searched_town_id_hi, map->last_searched_town_id_lo); + if (town) + msp->mr = binmap_search_street_by_place(map, town, &c, &msp->ms, &msp->boundaries); + if (msp->boundaries) + dbg(lvl_debug, "using map town boundaries"); + if (!msp->boundaries && town) { + binmap_get_estimated_boundaries(town, &msp->boundaries); + if (msp->boundaries) + dbg(lvl_debug, "using estimated boundaries"); + } + map_rect_destroy_binfile(map_rec); + /* start searching in area around the street segment even if town boundaries are available */ + msp->mr=binmap_search_housenumber_by_estimate(map, &c, &msp->ms); + msp->mode = 2; + msp->rect_new=msp->ms.u.c_rect; + if(item_attr_get(msp->item, attr_street_name, &attr)) + msp->parent_name=g_strdup(attr.u.str); + dbg(lvl_debug,"pn=%s",msp->parent_name); + } + } + if (idx != 3) { + map_rect_destroy_binfile(msp->mr_item); + msp->mr_item=NULL; + } + if (!msp->mr) { + break; + } + return msp; + default: + break; + } + if(ATTR_IS_STRING(msp->search.type)) + g_free(msp->search.u.str); + g_free(msp); + return NULL; +} + + +struct duplicate { + struct coord c; + char str[0]; }; -static guint -duplicate_hash(gconstpointer key) -{ - const struct duplicate *d=key; - return d->c.x^d->c.y^g_str_hash(d->str); +static guint duplicate_hash(gconstpointer key) { + const struct duplicate *d=key; + return d->c.x^d->c.y^g_str_hash(d->str); } -static gboolean -duplicate_equal(gconstpointer a, gconstpointer b) -{ - const struct duplicate *da=a; - const struct duplicate *db=b; - return (da->c.x == db->c.x && da->c.y == db->c.y && g_str_equal(da->str,db->str)); +static gboolean duplicate_equal(gconstpointer a, gconstpointer b) { + const struct duplicate *da=a; + const struct duplicate *db=b; + return (da->c.x == db->c.x && da->c.y == db->c.y && g_str_equal(da->str,db->str)); } /** @@ -2176,43 +2045,42 @@ duplicate_equal(gconstpointer a, gconstpointer b) * returns - pointer to new struct duplicate, if this item is not already exist in hash * - NULL if this item already exists in duplicate hash or doesnt have an attr_type attr; */ -static struct duplicate* -duplicate_test(struct map_search_priv *msp, struct item *item, enum attr_type attr_type, enum attr_type attr_type2) -{ -struct attr attr; - struct attr attr2; - int len; - char *buffer; - struct duplicate *d; - - if (!msp->search_results) - msp->search_results = g_hash_table_new_full(duplicate_hash, duplicate_equal, g_free, NULL); - binfile_attr_rewind(item->priv_data); - if (!item_attr_get(item, attr_type, &attr)) - return NULL; - len=sizeof(struct coord)+strlen(attr.u.str)+1; - binfile_attr_rewind(item->priv_data); - if (attr_type2 && item_attr_get(item, attr_type2, &attr2) && attr2.u.str) { - len = len + strlen(attr2.u.str); - } - buffer=g_alloca(sizeof(char)*len); - d=(struct duplicate *)buffer; - if (!item_coord_get(item, &d->c, 1)) { - d->c.x=0; - d->c.y=0; - } - strcpy(d->str, attr.u.str); - if(attr_type2 && attr2.u.str){ - strcat(d->str,attr2.u.str); - } - binfile_coord_rewind(item->priv_data); - binfile_attr_rewind(item->priv_data); - if (!g_hash_table_lookup(msp->search_results, d)) { - struct duplicate *dr=g_malloc(len); - memcpy(dr, d, len); - return dr; - } - return NULL; +static struct duplicate* duplicate_test(struct map_search_priv *msp, struct item *item, enum attr_type attr_type, + enum attr_type attr_type2) { + struct attr attr; + struct attr attr2; + int len; + char *buffer; + struct duplicate *d; + + if (!msp->search_results) + msp->search_results = g_hash_table_new_full(duplicate_hash, duplicate_equal, g_free, NULL); + binfile_attr_rewind(item->priv_data); + if (!item_attr_get(item, attr_type, &attr)) + return NULL; + len=sizeof(struct coord)+strlen(attr.u.str)+1; + binfile_attr_rewind(item->priv_data); + if (attr_type2 && item_attr_get(item, attr_type2, &attr2) && attr2.u.str) { + len = len + strlen(attr2.u.str); + } + buffer=g_alloca(sizeof(char)*len); + d=(struct duplicate *)buffer; + if (!item_coord_get(item, &d->c, 1)) { + d->c.x=0; + d->c.y=0; + } + strcpy(d->str, attr.u.str); + if(attr_type2 && attr2.u.str) { + strcat(d->str,attr2.u.str); + } + binfile_coord_rewind(item->priv_data); + binfile_attr_rewind(item->priv_data); + if (!g_hash_table_lookup(msp->search_results, d)) { + struct duplicate *dr=g_malloc(len); + memcpy(dr, d, len); + return dr; + } + return NULL; } /** @@ -2220,10 +2088,8 @@ struct attr attr; * @param msp pointer to private map search data * @param duplicate Duplicate info to insert */ -static void -duplicate_insert(struct map_search_priv *msp, struct duplicate *d) -{ - g_hash_table_insert(msp->search_results, d, GINT_TO_POINTER(1)); +static void duplicate_insert(struct map_search_priv *msp, struct duplicate *d) { + g_hash_table_insert(msp->search_results, d, GINT_TO_POINTER(1)); } /** @@ -2235,619 +2101,585 @@ duplicate_insert(struct map_search_priv *msp, struct duplicate *d) * @returns 0 if item is not a duplicate * 1 if item is duplicate or doesn't have required attr_type attribute */ -static int -duplicate(struct map_search_priv *msp, struct item *item, enum attr_type attr_type, enum attr_type attr_type2) -{ - struct duplicate *d=duplicate_test(msp, item, attr_type, attr_type2); - if(!d) - return 1; - duplicate_insert(msp,d); - return 0; +static int duplicate(struct map_search_priv *msp, struct item *item, enum attr_type attr_type, + enum attr_type attr_type2) { + struct duplicate *d=duplicate_test(msp, item, attr_type, attr_type2); + if(!d) + return 1; + duplicate_insert(msp,d); + return 0; } -static int -item_inside_poly_list(struct item *it, GList *l) -{ +static int item_inside_poly_list(struct item *it, GList *l) { - while(l) { - struct geom_poly_segment *p=l->data; - int count=p->last-p->first+1; - struct coord c; - int ccount; - item_coord_rewind(it); - ccount=binfile_coord_left(it->priv_data); - if(ccount==1) - item_coord_get(it,&c,1); - else if(ccount==2) { - struct coord c2; - item_coord_get(it,&c,1); - item_coord_get(it,&c2,1); - c.x=(c.x+c2.x)/2; - c.y=(c.y+c2.y)/2; - } else { - if(ccount>3) - ccount/=2; - else - ccount=2; - while(--ccount>0) - item_coord_get(it,&c,1); - } - if(geom_poly_point_inside(p->first,count,&c)) - return 1; - l=g_list_next(l); - } - return 0; -} - -static struct item * -binmap_search_get_item(struct map_search_priv *map_search) -{ - struct item* it; - struct attr at; - enum linguistics_cmp_mode mode=(map_search->partial?linguistics_cmp_partial:0); - - for (;;) { - while ((it = map_rect_get_item_binfile(map_search->mr))) { - int has_house_number=0; - switch (map_search->search.type) { - case attr_town_postal: - case attr_town_name: - case attr_district_name: - case attr_town_or_district_name: - if (map_search->mr->tile_depth > 1 && item_is_town(*it) && map_search->search.type == attr_town_postal) { - if (binfile_attr_get(it->priv_data, attr_town_postal, &at)) { - if (!linguistics_compare(at.u.str, map_search->search.u.str, mode)) { - /* check for duplicate combination of town_name and town_postal */ - if (!duplicate(map_search, it, attr_town_name, attr_town_postal)) { - return it; - } else { - break; - } - } - } - } - if (map_search->mr->tile_depth > 1 && item_is_town(*it) && map_search->search.type != attr_district_name) { - if (binfile_attr_get(it->priv_data, attr_town_name_match, &at) || binfile_attr_get(it->priv_data, attr_town_name, &at)) { - if (!linguistics_compare(at.u.str, map_search->search.u.str, mode) && !duplicate(map_search, it, attr_town_name,0)) - return it; - } - } - if (map_search->mr->tile_depth > 1 && item_is_district(*it) && map_search->search.type != attr_town_name) { - if (binfile_attr_get(it->priv_data, attr_district_name_match, &at) || binfile_attr_get(it->priv_data, attr_district_name, &at)) { - if (!linguistics_compare(at.u.str, map_search->search.u.str, mode) && !duplicate(map_search, it, attr_town_name,0)) - return it; - } - } - break; - case attr_street_name: - if (map_search->mode == 1) { - if (binfile_attr_get(it->priv_data, attr_street_name_match, &at) || binfile_attr_get(it->priv_data, attr_street_name, &at)) { - if (!linguistics_compare(at.u.str, map_search->search.u.str, mode) && !duplicate(map_search, it, attr_street_name,0)) { - return it; - } - } - continue; - } - if (item_is_street(*it)) { - struct attr at; - if (!map_selection_contains_item_rect(map_search->mr->sel, it)) - break; - - if(binfile_attr_get(it->priv_data, attr_label, &at)) { - struct coord c[128]; - struct duplicate *d; - - /* Extracting all coords here makes duplicate_new() not consider them (we don't want all - * street segments to be reported as separate streets). */ - while(item_coord_get(it,c,128)>0); - d=duplicate_test(map_search, it, attr_label,0); - if(!d) - break; - - if(linguistics_compare(at.u.str, map_search->search.u.str, mode|linguistics_cmp_expand|linguistics_cmp_words)) { - /* Remember this non-matching street name in duplicate hash to skip name - * comparison for its following segments */ - duplicate_insert(map_search, d); - break; - } - - if(map_search->boundaries && !item_inside_poly_list(it,map_search->boundaries)) { - /* Other segments may fit the town poly. Do not update hash for now. */ - g_free(d); - break; - } - - duplicate_insert(map_search, d); - item_coord_rewind(it); - return it; - } - } - break; - case attr_house_number: - has_house_number=binfile_attr_get(it->priv_data, attr_house_number, &at); - if ((has_house_number - || it->type == type_house_number_interpolation_even || it->type == type_house_number_interpolation_odd - || it->type == type_house_number_interpolation_all - || (map_search->mode == 1 && item_is_street(*it))|| it->type == type_house_number) - && !(map_search->boundaries && !item_inside_poly_list(it,map_search->boundaries))) - { - if (has_house_number) - { - struct attr at2; - if ((binfile_attr_get(it->priv_data, attr_street_name, &at2) || map_search->mode!=2) && !linguistics_compare(at.u.str, map_search->search.u.str, mode) - && !strcmp(at2.u.str, map_search->parent_name)) - { - if (!duplicate(map_search, it, attr_house_number,0)) - { - binfile_attr_rewind(it->priv_data); - return it; - } - } - } - else - { - struct attr at2; - if ((binfile_attr_get(it->priv_data, attr_street_name, &at2) || map_search->mode!=2) && !strcmp(at2.u.str, map_search->parent_name)) - { - if (!duplicate(map_search, it, attr_house_number_interpolation_no_ends_incrmt_2,0)) - { - binfile_attr_rewind(it->priv_data); - return it; - } - else if (!duplicate(map_search, it, attr_house_number_interpolation_no_ends_incrmt_1,0)) - { - binfile_attr_rewind(it->priv_data); - return it; - } - } else { - if (!( it->type == type_house_number_interpolation_even || it->type == type_house_number_interpolation_odd - || it->type == type_house_number_interpolation_all)) - return it; - } - - } - } else if( item_is_street(*it) && map_search->mode==2 && map_search->parent_name && binfile_attr_get(it->priv_data, attr_street_name, &at) && !strcmp(at.u.str, map_search->parent_name) ) - { - /* If matching street segment found, prepare to expand house number search region +100m around each way point */ - if (!(map_search->boundaries && !item_inside_poly_list(it,map_search->boundaries))) - { - struct coord c; - while(item_coord_get(it,&c,1)) - { - c.x-=100; - c.y-=100; - coord_rect_extend(&map_search->rect_new,&c); - c.x+=200; - c.y+=200; - coord_rect_extend(&map_search->rect_new,&c); - } - } - } - continue; - default: - return NULL; - } - } - if(map_search->search.type==attr_house_number && map_search->mode==2 && map_search->parent_name) { - /* For unindexed house number search, check if street segments extending possible housenumber locations were found */ - if(map_search->ms.u.c_rect.lu.x!=map_search->rect_new.lu.x || map_search->ms.u.c_rect.lu.y!=map_search->rect_new.lu.y || - map_search->ms.u.c_rect.rl.x!=map_search->rect_new.rl.x || map_search->ms.u.c_rect.rl.y!=map_search->rect_new.rl.y) { - map_search->ms.u.c_rect=map_search->rect_new; - map_rect_destroy_binfile(map_search->mr); - map_search->mr=map_rect_new_binfile(map_search->map, &map_search->ms); - dbg(lvl_debug,"Extended house number search region to %d x %d, restarting...\n",map_search->ms.u.c_rect.rl.x - map_search->ms.u.c_rect.lu.x, map_search->ms.u.c_rect.lu.y-map_search->ms.u.c_rect.rl.y); - continue; - } - } - if (!map_search->mr_item) - return NULL; - map_rect_destroy_binfile(map_search->mr); - if (!binmap_search_by_index(map_search->map, map_search->item, &map_search->mr)) - return NULL; - } -} - - -static void -binmap_search_destroy(struct map_search_priv *ms) -{ - if (ms->search_results) - g_hash_table_destroy(ms->search_results); - if(ATTR_IS_STRING(ms->search.type)) - g_free(ms->search.u.str); - if(ms->parent_name) - g_free(ms->parent_name); - if (ms->mr_item) - map_rect_destroy_binfile(ms->mr_item); - if (ms->mr) - map_rect_destroy_binfile(ms->mr); - while(ms->boundaries) { - geom_poly_segment_destroy(ms->boundaries->data); - ms->boundaries=g_list_delete_link(ms->boundaries,ms->boundaries); - } - g_free(ms); -} - -static int -binmap_get_attr(struct map_priv *m, enum attr_type type, struct attr *attr) -{ - attr->type=type; - switch (type) { - case attr_map_release: - if (m->map_release) { - attr->u.str=m->map_release; - return 1; - } - break; - case attr_progress: - if (m->progress) { - attr->u.str=m->progress; - return 1; - } - default: - break; - } - return 0; -} - -static int -binmap_set_attr(struct map_priv *map, struct attr *attr) -{ - switch (attr->type) { - case attr_update: - map->download_enabled = attr->u.num; - return 1; - default: - return 0; - } + while(l) { + struct geom_poly_segment *p=l->data; + int count=p->last-p->first+1; + struct coord c; + int ccount; + item_coord_rewind(it); + ccount=binfile_coord_left(it->priv_data); + if(ccount==1) + item_coord_get(it,&c,1); + else if(ccount==2) { + struct coord c2; + item_coord_get(it,&c,1); + item_coord_get(it,&c2,1); + c.x=(c.x+c2.x)/2; + c.y=(c.y+c2.y)/2; + } else { + if(ccount>3) + ccount/=2; + else + ccount=2; + while(--ccount>0) + item_coord_get(it,&c,1); + } + if(geom_poly_point_inside(p->first,count,&c)) + return 1; + l=g_list_next(l); + } + return 0; +} + +static struct item *binmap_search_get_item(struct map_search_priv *map_search) { + struct item* it; + struct attr at; + enum linguistics_cmp_mode mode=(map_search->partial?linguistics_cmp_partial:0); + + for (;;) { + while ((it = map_rect_get_item_binfile(map_search->mr))) { + int has_house_number=0; + switch (map_search->search.type) { + case attr_town_postal: + case attr_town_name: + case attr_district_name: + case attr_town_or_district_name: + if (map_search->mr->tile_depth > 1 && item_is_town(*it) && map_search->search.type == attr_town_postal) { + if (binfile_attr_get(it->priv_data, attr_town_postal, &at)) { + if (!linguistics_compare(at.u.str, map_search->search.u.str, mode)) { + /* check for duplicate combination of town_name and town_postal */ + if (!duplicate(map_search, it, attr_town_name, attr_town_postal)) { + return it; + } else { + break; + } + } + } + } + if (map_search->mr->tile_depth > 1 && item_is_town(*it) && map_search->search.type != attr_district_name) { + if (binfile_attr_get(it->priv_data, attr_town_name_match, &at) + || binfile_attr_get(it->priv_data, attr_town_name, &at)) { + if (!linguistics_compare(at.u.str, map_search->search.u.str, mode) && !duplicate(map_search, it, attr_town_name,0)) + return it; + } + } + if (map_search->mr->tile_depth > 1 && item_is_district(*it) && map_search->search.type != attr_town_name) { + if (binfile_attr_get(it->priv_data, attr_district_name_match, &at) + || binfile_attr_get(it->priv_data, attr_district_name, &at)) { + if (!linguistics_compare(at.u.str, map_search->search.u.str, mode) && !duplicate(map_search, it, attr_town_name,0)) + return it; + } + } + break; + case attr_street_name: + if (map_search->mode == 1) { + if (binfile_attr_get(it->priv_data, attr_street_name_match, &at) + || binfile_attr_get(it->priv_data, attr_street_name, &at)) { + if (!linguistics_compare(at.u.str, map_search->search.u.str, mode) && !duplicate(map_search, it, attr_street_name,0)) { + return it; + } + } + continue; + } + if (item_is_street(*it)) { + struct attr at; + if (!map_selection_contains_item_rect(map_search->mr->sel, it)) + break; + + if(binfile_attr_get(it->priv_data, attr_label, &at)) { + struct coord c[128]; + struct duplicate *d; + + /* Extracting all coords here makes duplicate_new() not consider them (we don't want all + * street segments to be reported as separate streets). */ + while(item_coord_get(it,c,128)>0); + d=duplicate_test(map_search, it, attr_label,0); + if(!d) + break; + + if(linguistics_compare(at.u.str, map_search->search.u.str, mode|linguistics_cmp_expand|linguistics_cmp_words)) { + /* Remember this non-matching street name in duplicate hash to skip name + * comparison for its following segments */ + duplicate_insert(map_search, d); + break; + } + + if(map_search->boundaries && !item_inside_poly_list(it,map_search->boundaries)) { + /* Other segments may fit the town poly. Do not update hash for now. */ + g_free(d); + break; + } + + duplicate_insert(map_search, d); + item_coord_rewind(it); + return it; + } + } + break; + case attr_house_number: + has_house_number=binfile_attr_get(it->priv_data, attr_house_number, &at); + if ((has_house_number + || it->type == type_house_number_interpolation_even || it->type == type_house_number_interpolation_odd + || it->type == type_house_number_interpolation_all + || (map_search->mode == 1 && item_is_street(*it))|| it->type == type_house_number) + && !(map_search->boundaries && !item_inside_poly_list(it,map_search->boundaries))) { + if (has_house_number) { + struct attr at2; + if ((binfile_attr_get(it->priv_data, attr_street_name, &at2) || map_search->mode!=2) + && !linguistics_compare(at.u.str, map_search->search.u.str, mode) + && !strcmp(at2.u.str, map_search->parent_name)) { + if (!duplicate(map_search, it, attr_house_number,0)) { + binfile_attr_rewind(it->priv_data); + return it; + } + } + } else { + struct attr at2; + if ((binfile_attr_get(it->priv_data, attr_street_name, &at2) || map_search->mode!=2) + && !strcmp(at2.u.str, map_search->parent_name)) { + if (!duplicate(map_search, it, attr_house_number_interpolation_no_ends_incrmt_2,0)) { + binfile_attr_rewind(it->priv_data); + return it; + } else if (!duplicate(map_search, it, attr_house_number_interpolation_no_ends_incrmt_1,0)) { + binfile_attr_rewind(it->priv_data); + return it; + } + } else { + if (!( it->type == type_house_number_interpolation_even || it->type == type_house_number_interpolation_odd + || it->type == type_house_number_interpolation_all)) + return it; + } + + } + } else if( item_is_street(*it) && map_search->mode==2 && map_search->parent_name + && binfile_attr_get(it->priv_data, attr_street_name, &at) && !strcmp(at.u.str, map_search->parent_name) ) { + /* If matching street segment found, prepare to expand house number search region +100m around each way point */ + if (!(map_search->boundaries && !item_inside_poly_list(it,map_search->boundaries))) { + struct coord c; + while(item_coord_get(it,&c,1)) { + c.x-=100; + c.y-=100; + coord_rect_extend(&map_search->rect_new,&c); + c.x+=200; + c.y+=200; + coord_rect_extend(&map_search->rect_new,&c); + } + } + } + continue; + default: + return NULL; + } + } + if(map_search->search.type==attr_house_number && map_search->mode==2 && map_search->parent_name) { + /* For unindexed house number search, check if street segments extending possible housenumber locations were found */ + if(map_search->ms.u.c_rect.lu.x!=map_search->rect_new.lu.x || map_search->ms.u.c_rect.lu.y!=map_search->rect_new.lu.y || + map_search->ms.u.c_rect.rl.x!=map_search->rect_new.rl.x || map_search->ms.u.c_rect.rl.y!=map_search->rect_new.rl.y) { + map_search->ms.u.c_rect=map_search->rect_new; + map_rect_destroy_binfile(map_search->mr); + map_search->mr=map_rect_new_binfile(map_search->map, &map_search->ms); + dbg(lvl_debug,"Extended house number search region to %d x %d, restarting...", + map_search->ms.u.c_rect.rl.x - map_search->ms.u.c_rect.lu.x, map_search->ms.u.c_rect.lu.y-map_search->ms.u.c_rect.rl.y); + continue; + } + } + if (!map_search->mr_item) + return NULL; + map_rect_destroy_binfile(map_search->mr); + if (!binmap_search_by_index(map_search->map, map_search->item, &map_search->mr)) + return NULL; + } +} + + +static void binmap_search_destroy(struct map_search_priv *ms) { + if (ms->search_results) + g_hash_table_destroy(ms->search_results); + if(ATTR_IS_STRING(ms->search.type)) + g_free(ms->search.u.str); + if(ms->parent_name) + g_free(ms->parent_name); + if (ms->mr_item) + map_rect_destroy_binfile(ms->mr_item); + if (ms->mr) + map_rect_destroy_binfile(ms->mr); + while(ms->boundaries) { + geom_poly_segment_destroy(ms->boundaries->data); + ms->boundaries=g_list_delete_link(ms->boundaries,ms->boundaries); + } + g_free(ms); +} + +static int binmap_get_attr(struct map_priv *m, enum attr_type type, struct attr *attr) { + attr->type=type; + switch (type) { + case attr_map_release: + if (m->map_release) { + attr->u.str=m->map_release; + return 1; + } + break; + case attr_progress: + if (m->progress) { + attr->u.str=m->progress; + return 1; + } + default: + break; + } + return 0; +} + +static int binmap_set_attr(struct map_priv *map, struct attr *attr) { + switch (attr->type) { + case attr_update: + map->download_enabled = attr->u.num; + return 1; + default: + return 0; + } } static struct map_methods map_methods_binfile = { - projection_mg, - "utf-8", - map_destroy_binfile, - map_rect_new_binfile, - map_rect_destroy_binfile, - map_rect_get_item_binfile, - map_rect_get_item_byid_binfile, - binmap_search_new, - binmap_search_destroy, - binmap_search_get_item, - NULL, - binmap_get_attr, - binmap_set_attr, + projection_mg, + "utf-8", + map_destroy_binfile, + map_rect_new_binfile, + map_rect_destroy_binfile, + map_rect_get_item_binfile, + map_rect_get_item_byid_binfile, + binmap_search_new, + binmap_search_destroy, + binmap_search_get_item, + NULL, + binmap_get_attr, + binmap_set_attr, }; -static int -binfile_get_index(struct map_priv *m) -{ - int len; - int cde_index_size; - int offset; - struct zip_cd *cd; - - len = strlen("index"); - cde_index_size = sizeof(struct zip_cd)+len; - if (m->eoc64) - offset = m->eoc64->zip64ecsz-cde_index_size; - else - offset = m->eoc->zipecsz-cde_index_size; - cd = binfile_read_cd(m, offset, len); - - if (!cd) { - cde_index_size+=sizeof(struct zip_cd_ext); - if (m->eoc64) - offset = m->eoc64->zip64ecsz-cde_index_size; - else - offset = m->eoc->zipecsz-cde_index_size; - cd = binfile_read_cd(m, offset, len+sizeof(struct zip_cd_ext)); - } - if (cd) { - if (cd->zipcfnl == len && !strncmp(cd->zipcfn, "index", len)) { - m->index_offset=offset; - m->index_cd=cd; - return 1; - } - } - offset=binfile_search_cd(m, 0, "index", 0, 0); - if (offset == -1) - return 0; - cd=binfile_read_cd(m, offset, -1); - if (!cd) - return 0; - m->index_offset=offset; - m->index_cd=cd; - return 1; -} - -static int -map_binfile_zip_setup(struct map_priv *m, char *filename, int mmap) -{ - struct zip_cd *first_cd; - int i; - if (!(m->eoc=binfile_read_eoc(m->fi))) { - dbg(lvl_error,"map file %s: unable to read eoc\n", filename); - return 0; - } - dbg_assert(m->eoc->zipedsk == m->eoc->zipecen); - if (m->eoc->zipedsk && strlen(filename) > 3) { - char *tmpfilename=g_strdup(filename),*ext=tmpfilename+strlen(tmpfilename)-3; - m->fis=g_new(struct file *,m->eoc->zipedsk); - for (i = 0 ; i < m->eoc->zipedsk-1 ; i++) { - sprintf(ext,"b%02d",i+1); - m->fis[i]=file_create(tmpfilename, 0); - if (mmap) - file_mmap(m->fis[i]); - } - m->fis[m->eoc->zipedsk-1]=m->fi; - g_free(tmpfilename); - } - dbg(lvl_debug,"num_disk %d\n",m->eoc->zipedsk); - m->eoc64=binfile_read_eoc64(m->fi); - if (!binfile_get_index(m)) { - dbg(lvl_error,"map file %s: no index found\n", filename); - return 0; - } - if (!(first_cd=binfile_read_cd(m, 0, 0))) { - dbg(lvl_error,"map file %s: unable to get first cd\n", filename); - return 0; - } - m->cde_size=sizeof(struct zip_cd)+first_cd->zipcfnl+first_cd->zipcxtl; - m->zip_members=m->index_offset/m->cde_size+1; - dbg(lvl_debug,"cde_size %d\n", m->cde_size); - dbg(lvl_debug,"members %d\n",m->zip_members); - file_data_free(m->fi, (unsigned char *)first_cd); - if (mmap) - file_mmap(m->fi); - return 1; +static int binfile_get_index(struct map_priv *m) { + int len; + int cde_index_size; + int offset; + struct zip_cd *cd; + + len = strlen("index"); + cde_index_size = sizeof(struct zip_cd)+len; + if (m->eoc64) + offset = m->eoc64->zip64ecsz-cde_index_size; + else + offset = m->eoc->zipecsz-cde_index_size; + cd = binfile_read_cd(m, offset, len); + + if (!cd) { + cde_index_size+=sizeof(struct zip_cd_ext); + if (m->eoc64) + offset = m->eoc64->zip64ecsz-cde_index_size; + else + offset = m->eoc->zipecsz-cde_index_size; + cd = binfile_read_cd(m, offset, len+sizeof(struct zip_cd_ext)); + } + if (cd) { + if (cd->zipcfnl == len && !strncmp(cd->zipcfn, "index", len)) { + m->index_offset=offset; + m->index_cd=cd; + return 1; + } + } + offset=binfile_search_cd(m, 0, "index", 0, 0); + if (offset == -1) + return 0; + cd=binfile_read_cd(m, offset, -1); + if (!cd) + return 0; + m->index_offset=offset; + m->index_cd=cd; + return 1; +} + +static int map_binfile_zip_setup(struct map_priv *m, char *filename, int mmap) { + struct zip_cd *first_cd; + int i; + if (!(m->eoc=binfile_read_eoc(m->fi))) { + dbg(lvl_error,"map file %s: unable to read eoc", filename); + return 0; + } + dbg_assert(m->eoc->zipedsk == m->eoc->zipecen); + if (m->eoc->zipedsk && strlen(filename) > 3) { + char *tmpfilename=g_strdup(filename),*ext=tmpfilename+strlen(tmpfilename)-3; + m->fis=g_new(struct file *,m->eoc->zipedsk); + for (i = 0 ; i < m->eoc->zipedsk-1 ; i++) { + sprintf(ext,"b%02d",i+1); + m->fis[i]=file_create(tmpfilename, 0); + if (mmap) + file_mmap(m->fis[i]); + } + m->fis[m->eoc->zipedsk-1]=m->fi; + g_free(tmpfilename); + } + dbg(lvl_debug,"num_disk %d",m->eoc->zipedsk); + m->eoc64=binfile_read_eoc64(m->fi); + if (!binfile_get_index(m)) { + dbg(lvl_error,"map file %s: no index found", filename); + return 0; + } + if (!(first_cd=binfile_read_cd(m, 0, 0))) { + dbg(lvl_error,"map file %s: unable to get first cd", filename); + return 0; + } + m->cde_size=sizeof(struct zip_cd)+first_cd->zipcfnl+first_cd->zipcxtl; + m->zip_members=m->index_offset/m->cde_size+1; + dbg(lvl_debug,"cde_size %d", m->cde_size); + dbg(lvl_debug,"members %d",m->zip_members); + file_data_free(m->fi, (unsigned char *)first_cd); + if (mmap) + file_mmap(m->fi); + return 1; } #if 0 -static int -map_binfile_download_initial(struct map_priv *m) -{ - struct attr readwrite={attr_readwrite,{(void *)1}}; - struct attr create={attr_create,{(void *)1}}; - struct attr *attrs[4]; - struct file *out; - long long woffset=0,planet_size; - int size_ret; - int cd1size,cdisize; - long long cd1offset,cdioffset; - struct zip64_eoc *zip64_eoc; - struct zip64_eocl *zip64_eocl; - struct zip_eoc *zip_eoc; - struct zip_cd *cd1,*cdn,*cdi; - int count,chunk,cdoffset=0; - int mode=1; - struct map_download *download=g_new0(struct map_download, 1); - - attrs[0]=&readwrite; - attrs[1]=&create; - attrs[2]=NULL; - download->file=file_create(m->filename,attrs); - download->m=m; - download_planet_size(download); - download_eoc(download); - download_directory_start(download); - while (download_directory_do(download)); - download_directory_finish(download); - download_initial_finish(download); - m->fi=download->file; - g_free(download); - return 1; - - - cd1size=sizeof(*cd1); - cd1offset=zip64_eoc->zip64eofst; - cd1=(struct zip_cd *)map_binfile_download_range(m, cd1offset, cd1size); - if (!cd1) - return 0; - cd1size=sizeof(*cd1)+binfile_cd_extra(cd1); - g_free(cd1); - cd1=(struct zip_cd *)map_binfile_download_range(m, cd1offset, cd1size); - if (!cd1) - return 0; - cd1->zipcunc=0; - cdisize=sizeof(*cdi)+strlen("index")+cd1->zipcxtl; - cdioffset=zip64_eoc->zip64eofst+zip64_eoc->zip64ecsz-cdisize; - cdi=(struct zip_cd *)map_binfile_download_range(m, cdioffset, cdisize); - if (!cdi) { - g_free(cd1); - return 0; - } - cdi->zipcunc=0; - cdn=g_malloc0(cd1size*256); - - file_data_write(out, woffset, sizeof(*zip64_eoc), (unsigned char *)zip64_eoc); - woffset+=sizeof(*zip64_eoc); - cdoffset=woffset; - - file_data_write(out, woffset, cd1size, (unsigned char *)cd1); - woffset+=cd1size; - count=(cdioffset-cd1offset)/cd1size-1; - while (count > 0) { - if (count > 256) - chunk=256; - else - chunk=count; - file_data_write(out, woffset, cd1size*chunk, (unsigned char *)cdn); - woffset+=cd1size*chunk; - count-=chunk; - } - g_free(cdn); - g_free(cd1); - file_data_write(out, woffset, cdisize, (unsigned char *)cdi); - woffset+=cdisize; +static int map_binfile_download_initial(struct map_priv *m) { + struct attr readwrite= {attr_readwrite,{(void *)1}}; + struct attr create= {attr_create,{(void *)1}}; + struct attr *attrs[4]; + struct file *out; + long long woffset=0,planet_size; + int size_ret; + int cd1size,cdisize; + long long cd1offset,cdioffset; + struct zip64_eoc *zip64_eoc; + struct zip64_eocl *zip64_eocl; + struct zip_eoc *zip_eoc; + struct zip_cd *cd1,*cdn,*cdi; + int count,chunk,cdoffset=0; + int mode=1; + struct map_download *download=g_new0(struct map_download, 1); + + attrs[0]=&readwrite; + attrs[1]=&create; + attrs[2]=NULL; + download->file=file_create(m->filename,attrs); + download->m=m; + download_planet_size(download); + download_eoc(download); + download_directory_start(download); + while (download_directory_do(download)); + download_directory_finish(download); + download_initial_finish(download); + m->fi=download->file; + g_free(download); + return 1; + + + cd1size=sizeof(*cd1); + cd1offset=zip64_eoc->zip64eofst; + cd1=(struct zip_cd *)map_binfile_download_range(m, cd1offset, cd1size); + if (!cd1) + return 0; + cd1size=sizeof(*cd1)+binfile_cd_extra(cd1); + g_free(cd1); + cd1=(struct zip_cd *)map_binfile_download_range(m, cd1offset, cd1size); + if (!cd1) + return 0; + cd1->zipcunc=0; + cdisize=sizeof(*cdi)+strlen("index")+cd1->zipcxtl; + cdioffset=zip64_eoc->zip64eofst+zip64_eoc->zip64ecsz-cdisize; + cdi=(struct zip_cd *)map_binfile_download_range(m, cdioffset, cdisize); + if (!cdi) { + g_free(cd1); + return 0; + } + cdi->zipcunc=0; + cdn=g_malloc0(cd1size*256); + + file_data_write(out, woffset, sizeof(*zip64_eoc), (unsigned char *)zip64_eoc); + woffset+=sizeof(*zip64_eoc); + cdoffset=woffset; + + file_data_write(out, woffset, cd1size, (unsigned char *)cd1); + woffset+=cd1size; + count=(cdioffset-cd1offset)/cd1size-1; + while (count > 0) { + if (count > 256) + chunk=256; + else + chunk=count; + file_data_write(out, woffset, cd1size*chunk, (unsigned char *)cdn); + woffset+=cd1size*chunk; + count-=chunk; + } + g_free(cdn); + g_free(cd1); + file_data_write(out, woffset, cdisize, (unsigned char *)cdi); + woffset+=cdisize; } #endif -static int -map_binfile_open(struct map_priv *m) -{ - int *magic; - struct map_rect_priv *mr; - struct item *item; - struct attr attr; - struct attr readwrite={attr_readwrite, {(void *)1}}; - struct attr *attrs[]={&readwrite, NULL}; - - dbg(lvl_debug,"file_create %s\n", m->filename); - m->fi=file_create(m->filename, m->url?attrs:NULL); - if (! m->fi && m->url) - return 0; - if (! m->fi) { - dbg(lvl_error,"Failed to load '%s'\n", m->filename); - return 0; - } - if (m->check_version) - m->version=file_version(m->fi, m->check_version); - magic=(int *)file_data_read(m->fi, 0, 4); - if (!magic) { - file_destroy(m->fi); - m->fi=NULL; - return 0; - } - *magic = le32_to_cpu(*magic); - if (*magic == zip_lfh_sig || *magic == zip_split_sig || *magic == zip_cd_sig || *magic == zip64_eoc_sig) { - if (!map_binfile_zip_setup(m, m->filename, m->flags & 1)) { - dbg(lvl_error,"invalid file format for '%s'\n", m->filename); - file_destroy(m->fi); - m->fi=NULL; - return 0; - } - } else if (*magic == zip_lfh_sig_rev || *magic == zip_split_sig_rev || *magic == zip_cd_sig_rev || *magic == zip64_eoc_sig_rev) { - dbg(lvl_error,"endianness mismatch for '%s'\n", m->filename); - file_destroy(m->fi); - m->fi=NULL; - return 0; - } else - file_mmap(m->fi); - file_data_free(m->fi, (unsigned char *)magic); - m->cachedir=g_strdup("/tmp/navit"); - m->map_version=0; - mr=map_rect_new_binfile(m, NULL); - if (mr) { - while ((item=map_rect_get_item_binfile(mr)) == &busy_item); - if (item && item->type == type_map_information) { - if (binfile_attr_get(item->priv_data, attr_version, &attr)) - m->map_version=attr.u.num; - if (binfile_attr_get(item->priv_data, attr_map_release, &attr)) - m->map_release=g_strdup(attr.u.str); - if (m->url && binfile_attr_get(item->priv_data, attr_url, &attr)) { - dbg(lvl_debug,"url config %s map %s\n",m->url,attr.u.str); - if (strcmp(m->url, attr.u.str)) - m->update_available=1; - g_free(m->url); - m->url=g_strdup(attr.u.str); - } - } - map_rect_destroy_binfile(mr); - if (m->map_version >= 16) { - dbg(lvl_error,"%s: This map is incompatible with your navit version. Please update navit. (map version %d)\n", - m->filename, m->map_version); - return 0; - } - } - return 1; -} - -static void -map_binfile_close(struct map_priv *m) -{ - int i; - file_data_free(m->fi, (unsigned char *)m->index_cd); - file_data_free(m->fi, (unsigned char *)m->eoc); - file_data_free(m->fi, (unsigned char *)m->eoc64); - g_free(m->cachedir); - g_free(m->map_release); - if (m->fis) { - for (i = 0 ; i < m->eoc->zipedsk ; i++) { - file_destroy(m->fis[i]); - } - } else - file_destroy(m->fi); -} - -static void -map_binfile_destroy(struct map_priv *m) -{ - g_free(m->filename); - g_free(m->url); - g_free(m->progress); - g_free(m); -} - - -static void -binfile_check_version(struct map_priv *m) -{ - int version=-1; - if (!m->check_version) - return; - if (m->fi) - version=file_version(m->fi, m->check_version); - if (version != m->version) { - if (m->fi) - map_binfile_close(m); - map_binfile_open(m); - } -} - - -static struct map_priv * -map_new_binfile(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl) -{ - struct map_priv *m; - struct attr *data=attr_search(attrs, NULL, attr_data); - struct attr *check_version,*flags,*url,*download_enabled; - struct file_wordexp *wexp; - char **wexp_data; - if (! data) - return NULL; - - wexp=file_wordexp_new(data->u.str); - wexp_data=file_wordexp_get_array(wexp); - dbg(lvl_debug,"map_new_binfile %s\n", data->u.str); - *meth=map_methods_binfile; - - m=g_new0(struct map_priv, 1); - m->cbl=cbl; - m->id=++map_id; - m->filename=g_strdup(wexp_data[0]); - file_wordexp_destroy(wexp); - check_version=attr_search(attrs, NULL, attr_check_version); - if (check_version) - m->check_version=check_version->u.num; - flags=attr_search(attrs, NULL, attr_flags); - if (flags) - m->flags=flags->u.num; - url=attr_search(attrs, NULL, attr_url); - if (url) - m->url=g_strdup(url->u.str); - download_enabled = attr_search(attrs, NULL, attr_update); - if (download_enabled) - m->download_enabled=download_enabled->u.num; - - if (!map_binfile_open(m) && !m->check_version && !m->url) { - map_binfile_destroy(m); - m=NULL; - } else { - load_changes(m); - } - return m; -} - -void -plugin_init(void) -{ - dbg(lvl_debug,"binfile: plugin_init\n"); - if (sizeof(struct zip_cd) != 46) { - dbg(lvl_error,"error: sizeof(struct zip_cd)=%zu\n",sizeof(struct zip_cd)); - } - plugin_register_category_map("binfile", map_new_binfile); +static int map_binfile_open(struct map_priv *m) { + int *magic; + struct map_rect_priv *mr; + struct item *item; + struct attr attr; + struct attr readwrite= {attr_readwrite, {(void *)1}}; + struct attr *attrs[]= {&readwrite, NULL}; + + dbg(lvl_debug,"file_create %s", m->filename); + m->fi=file_create(m->filename, m->url?attrs:NULL); + if (! m->fi && m->url) + return 0; + if (! m->fi) { + dbg(lvl_error,"Failed to load '%s'", m->filename); + return 0; + } + if (m->check_version) + m->version=file_version(m->fi, m->check_version); + magic=(int *)file_data_read(m->fi, 0, 4); + if (!magic) { + file_destroy(m->fi); + m->fi=NULL; + return 0; + } + *magic = le32_to_cpu(*magic); + if (*magic == zip_lfh_sig || *magic == zip_split_sig || *magic == zip_cd_sig || *magic == zip64_eoc_sig) { + if (!map_binfile_zip_setup(m, m->filename, m->flags & 1)) { + dbg(lvl_error,"invalid file format for '%s'", m->filename); + file_destroy(m->fi); + m->fi=NULL; + return 0; + } + } else if (*magic == zip_lfh_sig_rev || *magic == zip_split_sig_rev || *magic == zip_cd_sig_rev + || *magic == zip64_eoc_sig_rev) { + dbg(lvl_error,"endianness mismatch for '%s'", m->filename); + file_destroy(m->fi); + m->fi=NULL; + return 0; + } else + file_mmap(m->fi); + file_data_free(m->fi, (unsigned char *)magic); + m->cachedir=g_strdup("/tmp/navit"); + m->map_version=0; + mr=map_rect_new_binfile(m, NULL); + if (mr) { + while ((item=map_rect_get_item_binfile(mr)) == &busy_item); + if (item && item->type == type_map_information) { + if (binfile_attr_get(item->priv_data, attr_version, &attr)) + m->map_version=attr.u.num; + if (binfile_attr_get(item->priv_data, attr_map_release, &attr)) + m->map_release=g_strdup(attr.u.str); + if (m->url && binfile_attr_get(item->priv_data, attr_url, &attr)) { + dbg(lvl_debug,"url config %s map %s",m->url,attr.u.str); + if (strcmp(m->url, attr.u.str)) + m->update_available=1; + g_free(m->url); + m->url=g_strdup(attr.u.str); + } + } + map_rect_destroy_binfile(mr); + if (m->map_version >= 16) { + dbg(lvl_error,"%s: This map is incompatible with your navit version. Please update navit. (map version %d)", + m->filename, m->map_version); + return 0; + } + } + return 1; +} + +static void map_binfile_close(struct map_priv *m) { + int i; + file_data_free(m->fi, (unsigned char *)m->index_cd); + file_data_free(m->fi, (unsigned char *)m->eoc); + file_data_free(m->fi, (unsigned char *)m->eoc64); + g_free(m->cachedir); + g_free(m->map_release); + if (m->fis) { + for (i = 0 ; i < m->eoc->zipedsk ; i++) { + file_destroy(m->fis[i]); + } + } else + file_destroy(m->fi); +} + +static void map_binfile_destroy(struct map_priv *m) { + g_free(m->filename); + g_free(m->url); + g_free(m->progress); + g_free(m); +} + + +static void binfile_check_version(struct map_priv *m) { + int version=-1; + if (!m->check_version) + return; + if (m->fi) + version=file_version(m->fi, m->check_version); + if (version != m->version) { + if (m->fi) + map_binfile_close(m); + map_binfile_open(m); + } +} + + +static struct map_priv *map_new_binfile(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl) { + struct map_priv *m; + struct attr *data=attr_search(attrs, NULL, attr_data); + struct attr *check_version,*flags,*url,*download_enabled; + struct file_wordexp *wexp; + char **wexp_data; + if (! data) + return NULL; + + wexp=file_wordexp_new(data->u.str); + wexp_data=file_wordexp_get_array(wexp); + dbg(lvl_debug,"map_new_binfile %s", data->u.str); + *meth=map_methods_binfile; + + m=g_new0(struct map_priv, 1); + m->cbl=cbl; + m->id=++map_id; + m->filename=g_strdup(wexp_data[0]); + file_wordexp_destroy(wexp); + check_version=attr_search(attrs, NULL, attr_check_version); + if (check_version) + m->check_version=check_version->u.num; + flags=attr_search(attrs, NULL, attr_flags); + if (flags) + m->flags=flags->u.num; + url=attr_search(attrs, NULL, attr_url); + if (url) + m->url=g_strdup(url->u.str); + download_enabled = attr_search(attrs, NULL, attr_update); + if (download_enabled) + m->download_enabled=download_enabled->u.num; + + if (!map_binfile_open(m) && !m->check_version && !m->url) { + map_binfile_destroy(m); + m=NULL; + } else { + load_changes(m); + } + return m; +} + +void plugin_init(void) { + dbg(lvl_debug,"binfile: plugin_init"); + if (sizeof(struct zip_cd) != 46) { + dbg(lvl_error,"error: sizeof(struct zip_cd)=%zu",sizeof(struct zip_cd)); + } + plugin_register_category_map("binfile", map_new_binfile); } |