/** * ZANavi, Zoff Android Navigation system. * Copyright (C) 2011-2012 Zoff * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * Navit, a modular navigation system. * Copyright (C) 2005-2008 Navit Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "config.h" #include "debug.h" #include "plugin.h" #include "projection.h" #include "item.h" #include "map.h" #include "maptype.h" #include "attr.h" #include "coord.h" #include "transform.h" #include "file.h" #include "zipfile.h" #include "linguistics.h" #include "endianess.h" #include "callback.h" #include "types.h" #include "navit.h" static int map_id; struct tile { int *start; int *end; int *pos; int *pos_coord_start; int *pos_coord; int *pos_attr_start; int *pos_attr; int *pos_next; struct file *fi; 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; }; struct map_priv { int id; char *filename; 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 *passwd; 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; }; 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; #ifdef DEBUG_SIZE int size; #endif }; struct map_search_priv { struct map_priv *map; struct map_rect_priv *mr; struct map_rect_priv *mr_item; struct item *item; struct attr *search; struct map_selection ms; int partial; int mode; GHashTable *search_results; char *str; }; static void push_tile(struct map_rect_priv *mr, struct tile *t, int offset, int length); static void setup_pos(struct map_rect_priv *mr); static void map_binfile_close(struct map_priv *m); 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) { // dbg(0,"_endian 3\n"); 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) { // dbg(0,"_endian 1\n"); 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) { // dbg(0,"_endian 2\n"); 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(0, "sig 0x%x\n", eoc->zipesig); if (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(0, "sig 0x%x\n", eocl->zip64lsig); if (eocl->zip64lsig != zip64_eocl_sig) { file_data_free(fi, (unsigned char *) eocl); //dbg(0, "eocl wrong\n"); 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(0, "eoc wrong\n"); eoc = NULL; } //dbg(0, "eoc64 ok 0x%Lx 0x%Lx\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) { //dbg(0,"_enter\n"); struct zip_cd *cd; long long cdoffset = m->eoc64 ? m->eoc64->zip64eofst : m->eoc->zipeofst; //dbg(0,"_cdoffset="LONGLONG_FMT"\n", cdoffset); if (len == -1) { //dbg(0,"_len = -1\n"); cd = (struct zip_cd *) file_data_read(m->fi, cdoffset + offset, sizeof(*cd)); cd_to_cpu(cd); len = binfile_cd_extra(cd); //dbg(0,"_len = %d\n", len); 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(0,"cd at "LONGLONG_FMT" %d bytes\n",cdoffset+offset, sizeof(*cd)+len); cd_to_cpu(cd); //dbg(0, "sig 0x%x\n", cd->zipcensig); if (cd->zipcensig != zip_cd_sig) { file_data_free(m->fi, (unsigned char *) cd); //dbg(0,"_cd=NULL\n"); cd = NULL; } } //dbg(0,"leave\n"); return cd; } static struct zip_cd_ext * binfile_cd_ext(struct zip_cd *cd) { struct zip_cd_ext *ext; if (cd->zipofst != 0xffffffff) return NULL; if (cd->zipcxtl != sizeof(*ext)) return NULL; ext = (struct zip_cd_ext *) ((unsigned char *) cd + sizeof(*cd) + cd->zipcfnl); if (ext->tag != 0x0001 || ext->size != 8) return NULL; return ext; } 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) { struct zip_enc *enc; 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; case 99: if (!m->passwd) { break; } enc = (struct zip_enc *) file_data_read(fi, offset, sizeof(*enc)); offset += lfh->zipxtraln; switch (enc->compress_method) { case 0: ret = file_data_read_encrypted(fi, offset, lfh->zipsize, lfh->zipuncmp, 0, m->passwd); break; case 8: ret = file_data_read_encrypted(fi, offset, lfh->zipsize, lfh->zipuncmp, 1, m->passwd); break; default: // dbg(0, "Unknown encrypted compression method %d\n", enc->compress_method); break; } file_data_free(fi, (unsigned char *) enc); break; default: // dbg(0, "Unknown compression method %d\n", lfh->zipmthd); break; } return ret; } static int binfile_search_cd(struct map_priv *m, int offset, char *name, int partial, int skip) { //dbg(0,"_enter\n"); 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(0,"end=%d\n",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) { #if 0 // dbg(0,"reload %p %d %d\n", 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 0 // dbg(0,"offset=%d search_offset=%d search_size=%d search_data=%p cd=%p\n", offset, m->search_offset, m->search_size, m->search_data, cd); // dbg(0,"offset=%d fn='%s'\n",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(1, "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 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 = (t->pos_attr_start - t->pos_coord) / 2; if (count > max) { count = max; } #if __BYTE_ORDER == __LITTLE_ENDIAN 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++; } } #endif t->pos_coord += count * 2; ret = count; return ret; } 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(0, "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) { #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:enter\n"); #endif // try to return "0" on any problem, to avoid crash!! 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) { //dbg(0,"batg:002 %d %d\n",t->pos_attr,(t->pos_attr+1)); size = le32_to_cpu(*(t->pos_attr++)); // dbg(0,"batg:002.1 %d %d\n",t->pos_attr, t->pos_attr[0]); type = le32_to_cpu(t->pos_attr[0]); // dbg(0, "type=%d\n", type); #ifdef NAVIT_ATTR_SAFETY_CHECK // safety check (always keep value in sync with "attr_def.h" !!) --------------- if (type > 0x000effff) { return 0; } // safety check (always keep value in sync with "attr_def.h" !!) --------------- #endif //dbg(0,"batg:002.2\n"); 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(1, "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 |= NAVIT_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; } } } #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave\n"); #endif return 0; } struct binfile_hash_entry { 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 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(0, "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_func, NULL); g_hash_table_replace(m->changes, entry, entry); // dbg(0, "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(0, "Before: pos_coord=%d\n", t->pos_coord - i); //while (i < t->pos_next) //{ // // dbg(0, "%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(0, "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(0, "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(0, "moving %d ints from offset %d to %d\n", move_len, tn->pos_coord_start + move_offset - data, tn->pos_coord_start + move_offset + delta - data); memmove(tn->pos_coord_start + move_offset + delta, tn->pos_coord_start + move_offset, move_len * 4); //{ //int *i = tn->pos, j = 0; // dbg(0, "After move: pos_coord=%d\n", tn->pos_coord - i); //while (i < tn->pos_next) //{ // // dbg(0, "%d:0x%x\n", j++, *i++); //} //} if (mode != change_mode_append) { tn->pos_coord += move_offset; } if (mode != change_mode_delete) { // dbg(0, "writing %d ints at offset %d\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(0, "After: pos_coord=%d\n", tn->pos_coord - i); //while (i < tn->pos_next) //{ // // dbg(0, "%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 extend, 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(0, "Before: pos_attr=%d\n", t->pos_attr - i); //while (i < t->pos_next) //{ // // dbg(0, "%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(0, "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(0, "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; extend = 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(0, "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(0, "attr start %d offset %d\n", tn->pos_attr_start - data, offset); // dbg(0, "moving %d ints from offset %d to %d\n", move_len, tn->pos_attr_start + move_offset - data, tn->pos_attr_start + move_offset + delta - data); 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(0, "After move: pos_attr=%d\n", tn->pos_attr - i); while (i < tn->pos_next) { // dbg(0, "%d:0x%x\n", j++, *i++); } } if (nattr_len) { int *nattr = tn->pos_attr_start + write_offset; // dbg(0, "writing %d ints at %d\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(0, "After: pos_attr=%d\n", tn->pos_attr - i); //while (i < tn->pos_next) //{ // // dbg(0, "%d:0x%x\n", 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, }; 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(0,"leave %d\n",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(1, "enter %p %p %p\n", m, cd, t); // dbg(1, "cd->zipofst=0x%Lx\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; // dbg(1, "0x%x '%s' %d %d,%d\n", lfh->ziplocsig, buffer, sizeof(*cd) + cd->zipcfnl, lfh->zipsize, lfh->zipuncmp); 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(0, "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(1,"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(0, "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(0, "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(0, "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(0,"encountered missing tile %d %s(%s), Downloading %d bytes at "LONGLONG_FMT"\n",download->zipfile, url.u.str,(char *)(download->cd_copy+1), download->dl_size, download->offset); 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(1,"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(1, "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(0,"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(0,"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; } 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(1, "size_ret=%d\n", size_ret); if (!size_ret) return 0; if (size_ret != sizeof(*cd) || cd->zipcensig != zip_cd_sig) { // dbg(0, "error1 size=%d vs %d\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(0, "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_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); #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; } 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; // dbg(1, "enter %p %d\n", 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(0,"enter %d (%s) %d\n",zipfile, filename, cd->zipcunc); } #endif 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(0, "state=%d\n", download->state); switch (download->state) { case 0: // dbg(0, "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(0, "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(1,"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(1, "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 = { { -20000000, 20000000 }, /* lu */ { 20000000, -20000000 }, /* rl */ }; *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) { //// dbg(0,"EEnter\n"); 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(1, "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(0, "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_func, 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(0,"size=%d kb\n",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(0, "size=0x%x\n", size); #if 0 fprintf(stderr,"offset=%d\n", (unsigned char *)(mr->pos)-mr->m->f->begin); #endif // dbg(0, "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) { //// dbg(0,"EEnter\n"); int order; if (!sel) return 1; while (sel) { if (coord_rect_overlap(r, &sel->u.c_rect)) { order = sel->order; // dbg(1, "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)) { if (at.u.num == mr->country_id) { if (binfile_attr_get(mr->item.priv_data, attr_zipfile_ref, &at)) { 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(1, "pushing zipfile %d 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) { #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:enter\n"); #endif struct tile *t; struct map_priv *m = mr->m; if (m->download) { download(m, NULL, NULL, 0, 0, 0, 2); #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave9\n"); #endif return &busy_item; } if (mr->status == 1) { mr->status = 0; if (push_zipfile_tile(mr, m->zip_members - 1, 0, 0, 1)) { #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave8\n"); #endif return &busy_item; } } for (;;) { t = mr->t; if (!t) { #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave6\n"); #endif return NULL; } t->pos = t->pos_next; if (t->pos >= t->end) { if (pop_tile(mr)) { continue; } #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave5\n"); #endif 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)) { #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave4\n"); #endif 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)) { #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave3\n"); #endif return &mr->item; } else { continue; } } #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave 2\n"); #endif return &mr->item; } #ifdef NAVIT_FUNC_CALLS_DEBUG_PRINT dbg(0,"+#+:leave\n"); #endif } 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) { 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[128]; int i, count; found = 1; while ((count = item_coord_get(place, c, 128))) { for (i = 0; i < count; i++) { coord_rect_extend(&sel->u.c_rect, &c[i]); } } } } map_rect_destroy_binfile(map_rec2); if (found) { return map_rect_new_binfile(map, sel); } return NULL; } 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 = 10000; switch (town->type) { case type_town_label_1e7: case type_town_label_5e6: case type_town_label_2e6: case type_town_label_1e6: case type_town_label_5e5: case type_town_label_2e5: size = 10000; break; case type_town_label_1e5: case type_town_label_5e4: case type_town_label_2e4: size = 5000; break; case type_town_label_1e4: case type_town_label_5e3: case type_town_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: size = 1000; break; default: break; } if (global_search_street_size_factor > 1) { size = size * global_search_street_size_factor; } 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 = 20; 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; //sel->next = NULL; return map_rect_new_binfile(map, sel); } 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 willsearch = 0; msp->search = search; msp->partial = partial; /* * 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: map_rec = map_rect_new_binfile(map, NULL); if (!map_rec) { break; } map_rec->country_id = item->id_lo; msp->mr = map_rec; willsearch = 1; break; case attr_town_postal: 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)) { //dbg(0, "search:mode=1\n"); msp->mode = 1; } else { if (item_coord_get(town, &c, 1)) { if ((msp->mr = binmap_search_street_by_place(map, town, &c, &msp->ms))) { //dbg(0, "search:mode=2\n"); msp->mode = 2; } else { msp->mr = binmap_search_street_by_estimate(map, town, &c, &msp->ms); //dbg(0, "search:mode=3\n"); msp->mode = 3; } } } map_rect_destroy_binfile(map_rec); if (!msp->mr) { break; } willsearch = 1; break; } map_rect_destroy_binfile(map_rec); break; case attr_house_number: // dbg(1, "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); if (binmap_search_by_index(map, msp->item, &msp->mr) != 3) { struct coord c; if (item_coord_get(msp->item, &c, 1)) { msp->mr = binmap_search_housenumber_by_estimate(map, &c, &msp->ms); msp->mode = 2; } map_rect_destroy_binfile(msp->mr_item); msp->mr_item = NULL; } if (!msp->mr) { break; } willsearch = 1; break; default: break; } if (!willsearch) { g_free(msp); msp = NULL; } else { msp->str = linguistics_casefold(search->u.str); } return msp; } static int ascii_cmp(char *name, char *match, int partial) { int ret = 1; if (name == NULL) { return ret; } if (match == NULL) { return ret; } char *s2 = linguistics_casefold(match); // user entered search string char *s1 = linguistics_casefold(name); // string from mapfile char *s1_1 = linguistics_expand_special(s1, 1); char *s2_1 = linguistics_expand_special(s2, 1); if (s1_1) { if (s2_1) { ret = linguistics_compare(s1_1, s2_1, partial); } else { ret = linguistics_compare(s1_1, s2, partial); } } else { if (s2_1) { ret = linguistics_compare(s1, s2_1, partial); } else { ret = linguistics_compare(s1, s2, partial); } } if (s1_1) g_free(s1_1); if (s2_1) g_free(s2_1); if (s1) g_free(s1); if (s2) g_free(s2); return ret; } 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 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 == da->c.y && g_str_equal(da->str, db->str)); } static int duplicate(struct map_search_priv *msp, struct item *item, enum attr_type attr_type) { struct attr attr; if (!msp->search_results) msp->search_results = g_hash_table_new_full(duplicate_hash, duplicate_equal, g_free_func, NULL); binfile_attr_rewind(item->priv_data); if (!item_attr_get(item, attr_type, &attr)) return 1; { int len = sizeof(struct coord) + strlen(attr.u.str) + 1; char *buffer = g_alloca(sizeof(char) * len); struct duplicate *d = (struct duplicate *) buffer; if (!item_coord_get(item, &d->c, 1)) { d->c.x = 0; d->c.y = 0; } binfile_coord_rewind(item->priv_data); strcpy(d->str, attr.u.str); if (!g_hash_table_lookup(msp->search_results, d)) { struct duplicate *dc = g_malloc(len); memcpy(dc, d, len); g_hash_table_insert(msp->search_results, dc, GINT_TO_POINTER(1)); binfile_attr_rewind(item->priv_data); return 0; } } return 2; } static struct item * binmap_search_get_item(struct map_search_priv *map_search) { struct item* it; struct attr at; // // dbg(0,"Enter\n"); for (;;) { while ((it = map_rect_get_item_binfile(map_search->mr))) { switch (map_search->search->type) { case attr_town_name: case attr_district_name: case attr_town_or_district_name: #if 0 if (map_search->mr->tile_depth > 1 && item_is_town(*it) && !item_is_district(*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 (!ascii_cmp(at.u.str, map_search->str, map_search->partial) && !duplicate(map_search, it, attr_town_name)) return it; } } #endif #if 1 if (map_search->mr->tile_depth > 1 && item_is_town(*it) && !item_is_district(*it) && map_search->search->type != attr_district_name) { if (binfile_attr_get(it->priv_data, attr_town_name, &at)) { //// dbg(0,"22town n:%s\n",at.u.str); if (!ascii_cmp(at.u.str, map_search->str, map_search->partial) // && !duplicate(map_search, it, attr_town_name) ) { //// dbg(0,"town n:%s\n",at.u.str); return it; } } if (binfile_attr_get(it->priv_data, attr_town_name_match, &at)) { //// dbg(0,"11town M:%s\n",at.u.str); if (!ascii_cmp(at.u.str, map_search->str, map_search->partial) // && !duplicate(map_search, it, attr_town_name) ) { //// dbg(0,"town M:%s\n",at.u.str); return it; } } } #endif 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 (!ascii_cmp(at.u.str, map_search->str, map_search->partial) && !duplicate(map_search, it, attr_town_name)) return it; } } break; case attr_street_name: if (map_search->mode == 1) { //dbg(0,"*in here 00*\n"); //if (binfile_attr_get(it->priv_data, attr_street_name_match, &at) || binfile_attr_get(it->priv_data, attr_street_name, &at)) { // if (!ascii_cmp(at.u.str, map_search->str, map_search->partial) && !duplicate(map_search, it, attr_street_name)) { // return it; // } //} if (binfile_attr_get(it->priv_data, attr_street_name, &at)) { //// dbg(0,"str AA:%s\n", at.u.str); if (!ascii_cmp(at.u.str, map_search->str, map_search->partial)) { if ((offline_search_filter_duplicates != 1) || (!duplicate(map_search, it, attr_street_name))) { return it; } else { //// dbg(0,"dup street 1:%s\n",at.u.str); } } } if (binfile_attr_get(it->priv_data, attr_street_name_match, &at)) { //// dbg(0,"str BB:%s\n", at.u.str); if (!ascii_cmp(at.u.str, map_search->str, map_search->partial)) { if ((offline_search_filter_duplicates != 1) || (!duplicate(map_search, it, attr_street_name_match))) { return it; } else { //// dbg(0,"dup street 2:%s\n",at.u.str); } } } continue; } #if 1 // ------------------------------------ // map_search->mode == 2 or 3 // ------------------------------------ if (item_is_street(*it)) { // dbg(0,"*in here 11*\n"); struct attr at; if (map_selection_contains_item_rect(map_search->mr->sel, it)) { if (binfile_attr_get(it->priv_data, attr_label, &at)) { int match = 0; char *str = g_strdup(at.u.str); // dbg(0,"search=%s str is:%s\n",map_search->str, at.u.str); if (!ascii_cmp(str, map_search->str, map_search->partial)) { match = 1; } g_free(str); if (match) { if ((offline_search_filter_duplicates != 1) || (!duplicate(map_search, it, attr_label))) { item_coord_rewind(it); return it; } } } if (binfile_attr_get(it->priv_data, attr_street_name_match, &at)) { int match = 0; char *str = g_strdup(at.u.str); // dbg(0,"search=%s mstr is:%s\n",map_search->str, at.u.str); if (!ascii_cmp(str, map_search->str, map_search->partial)) { match = 1; } g_free(str); if (match) { if ((offline_search_filter_duplicates != 1) || (!duplicate(map_search, it, attr_street_name_match))) { item_coord_rewind(it); return it; } } } //else //{ // if (binfile_attr_get(it->priv_data, attr_street_name, &at)) // { // // dbg(0,"---str X*X:%s\n", at.u.str); // } //} } } #endif break; case attr_house_number: //if (it->type == type_house_number) if ((it->type == type_house_number) || (type_house_number_interpolation_even) || (type_house_number_interpolation_odd) || (type_house_number_interpolation_all)) { // is it a housenumber? if (binfile_attr_get(it->priv_data, attr_house_number, &at)) { // match housenumber to our string if (!ascii_cmp(at.u.str, map_search->str, map_search->partial)) { //binfile_attr_get(it->priv_data, attr_street_name, &at); //// dbg(0,"hnnn B1 street_name=%s",at.u.str); if (!duplicate(map_search, it, attr_house_number)) { binfile_attr_rewind(it->priv_data); return it; } } } else { return it; } } continue; default: return NULL; } } 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; } } // endless for-loop return NULL; // this is never reached } static void binmap_search_destroy(struct map_search_priv *ms) { if (ms->search_results) g_hash_table_destroy(ms->search_results); if (ms->mr_item) map_rect_destroy_binfile(ms->mr_item); if (ms->mr) map_rect_destroy_binfile(ms->mr); if (ms->str) g_free(ms->str); 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, }; static int binfile_get_index(struct map_priv *m) { //dbg(0,"_enter\n"); int len; int cde_index_size; long long offset; // int or long long ? struct zip_cd *cd; len = strlen("index"); cde_index_size = sizeof(struct zip_cd) + len; //dbg(0,"_cde_index_size=%d\n", cde_index_size); if (m->eoc64) { //dbg(0,"_m->eoc64->zip64ecsz=%d\n", m->eoc64->zip64ecsz); offset = m->eoc64->zip64ecsz - cde_index_size; //dbg(0,"_eoc64 offset="LONGLONG_FMT"\n", offset); } else { //dbg(0,"_m->eoc->zipecsz=%d\n", m->eoc->zipecsz); offset = m->eoc->zipecsz - cde_index_size; //dbg(0,"_eoc offset="LONGLONG_FMT"\n", offset); } cd = binfile_read_cd(m, offset, len); if (!cd) { //dbg(0,"_!cd\n"); cde_index_size += sizeof(struct zip_cd_ext); //dbg(0,"_cde_index_size=%d\n", cde_index_size); if (m->eoc64) { offset = m->eoc64->zip64ecsz - cde_index_size; //dbg(0,"_eoc64 offset aa.1="LONGLONG_FMT"\n", offset); } else { offset = m->eoc->zipecsz - cde_index_size; //dbg(0,"_offset 22.0="LONGLONG_FMT"\n", offset); } cd = binfile_read_cd(m, offset, len + sizeof(struct zip_cd_ext)); } //dbg(0,"_offset 22="LONGLONG_FMT"\n", offset); if (cd) { //dbg(0,"_cd 001\n"); if (cd->zipcfnl == len && !strncmp(cd->zipcfn, "index", len)) { m->index_offset = offset; m->index_cd = cd; //dbg(0,"_leave:offset 33="LONGLONG_FMT"\n", offset); return 1; } //dbg(0,"_cd 002\n"); } offset = binfile_search_cd(m, 0, "index", 0, 0); //dbg(0,"_offset 44="LONGLONG_FMT"\n", offset); if (offset == -1) { //dbg(0,"_leave:55\n"); return 0; } cd = binfile_read_cd(m, offset, -1); if (!cd) { //dbg(0,"_leave:66\n"); return 0; } m->index_offset = offset; m->index_cd = cd; //dbg(0,"_leave:normal:offset 77="LONGLONG_FMT"\n", offset); return 1; } static int map_binfile_zip_setup(struct map_priv *m, char *filename, int mmap) { //dbg(0,"_enter\n"); struct zip_cd *first_cd; int i; if (!(m->eoc = binfile_read_eoc(m->fi))) { //dbg(0,"_leave:1\n"); return 0; } dbg_assert(m->eoc->zipedsk == m->eoc->zipecen); if (m->eoc->zipedsk && strlen(filename) > 3) { char *tmpfilename = g_strdup(filename); char *ext = tmpfilename + strlen(tmpfilename) - 3; //dbg(0,"_ff-1:%s\n", tmpfilename); //dbg(0,"_ff-2:%s\n", ext); m->fis=g_new(struct file *,m->eoc->zipedsk); for (i = 0; i < m->eoc->zipedsk - 1; i++) { sprintf(ext, "b%02d", i + 1); //dbg(0,"_ff--3:%s\n", ext); m->fis[i] = file_create(tmpfilename, 0); if (mmap) { //dbg(0,"_want mmap 2 %s\n", m->fis[i]->name); file_mmap(m->fis[i]); } } m->fis[m->eoc->zipedsk - 1] = m->fi; g_free(tmpfilename); } else { //dbg(0,"_ff-XX\n"); } //dbg(0, "_num_disk %d\n", m->eoc->zipedsk); m->eoc64 = binfile_read_eoc64(m->fi); if (!binfile_get_index(m)) { //dbg(0,"_leave:2\n"); return 0; } if (!(first_cd = binfile_read_cd(m, 0, 0))) { //dbg(0,"_leave:3\n"); 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(0, "_cde_size %d\n", m->cde_size); //dbg(0, "_members %d\n", m->zip_members); file_data_free(m->fi, (unsigned char *) first_cd); if (mmap) { //dbg(0,"_want mmap 3 %s\n", m->fi->name); 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; } #endif static int string_endswith(const char* ending, const char* instring) { int l1; int l2; if (!ending) { return 0; } if (!instring) { return 0; } l1 = strlen(ending); l2 = strlen(instring); if (l1 < 1) { return 0; } if (l1 > l2) { return 0; } int ret = strcmp(ending, instring + (l2 - l1)); //dbg(0, "ending=%s in=%s ret=%d\n", ending, instring + (l2 - l1), (ret == 0)); return (ret == 0); } static int map_binfile_open(struct map_priv *m) { int *magic; int version_exception = 0; struct map_rect_priv *mr; struct item *item; struct attr attr; struct attr readwrite = { attr_readwrite, { (void *) 1 } }; struct attr *attrs[] = { &readwrite, NULL }; // dbg(0, "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(0, "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; } //dbg(0,"_zip_lfh_sig=%d\n", zip_lfh_sig); //dbg(0,"_magic1=%d\n", magic[0]); //dbg(0,"_magic1=%d\n", magic[1]); //dbg(0,"_magic1=%d\n", magic[2]); //dbg(0,"_magic1=%d\n", magic[3]); *magic = le32_to_cpu(*magic); //dbg(0,"_magic2=%d\n", magic[0]); //dbg(0,"_magic2=%d\n", magic[1]); //dbg(0,"_magic2=%d\n", magic[2]); //dbg(0,"_magic2=%d\n", magic[3]); 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(0, "invalid file format for '%s'\n", m->filename); file_destroy(m->fi); m->fi = NULL; return 0; } } else { //dbg(0,"_want mmap %s\n", m->fi->name); file_mmap(m->fi); } //dbg(0,"_cont\n"); 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; dbg(0, "map version=%d\n", m->map_version); } if (binfile_attr_get(item->priv_data, attr_map_release, &attr)) { m->map_release = g_strdup(attr.u.str); dbg(0, "maptool version used=%s\n", m->map_release); } if (string_endswith("borders.bin", m->filename) == 1) { dbg(0, "map exception added!\n"); version_exception = 1; } if (string_endswith("coastline.bin", m->filename) == 1) { dbg(0, "map exception added!\n"); version_exception = 1; } //if (m->url && binfile_attr_get(item->priv_data, attr_url, &attr)) //{ // dbg(0, "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 (version_exception == 0) { if (m->map_version < (int)NEED_MIN_BINFILE_MAPVERSION) { dbg(0, "!!**Warning**!!: This map is too old for your version of ZANavi. You need at least a version %d map\n", (int)NEED_MIN_BINFILE_MAPVERSION); 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, *map_pass, *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(0, "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(data->u.str); // file_wordexp_destroy(wexp); check_version = attr_search(attrs, NULL, attr_check_version); if (check_version) m->check_version = check_version->u.num; map_pass = attr_search(attrs, NULL, attr_map_pass); if (map_pass) m->passwd = g_strdup(map_pass->u.str); 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(1, "binfile: plugin_init\n"); if (sizeof(struct zip_cd) != 46) { // dbg(0, "error: sizeof(struct zip_cd)=%d\n", sizeof(struct zip_cd)); } plugin_register_map_type("binfile", map_new_binfile); }