/*************************************************************************** * map_loadsave.c * * Thu Jul 19 19:00:10 2007 * Copyright 2007 Steffen Pohle * steffen@gulpe.de ****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_LOCALE_H #include #endif #include #include #include #include #include #include #include "map.h" #include "system.h" #include "memoryleak.h" #include "osmroute.h" #define MAP_BITS_SUBID 5 char *lsrw_data = NULL; int lsrw_data_size = 0; char *lshash_data = NULL; int lshash_data_size = 0; /******************************************************************* * create filename out of the ilon and ilat field. */ void map_ls_get_filename_only (char *fn, int len, int ilon, int ilat) { int flon, flat; flon = ilon/MAP_LSHASHFACTOR; flat = ilat/MAP_LSHASHFACTOR; #ifdef HAVE_LOCALE_H setlocale(LC_ALL, "C"); snprintf (fn, len, "mlon%dlat%d.mapdata", flon, flat); setlocale(LC_ALL, NULL); #else snprintf (fn, len, "mlon%dlat%d.mapdata", flon, flat); #endif }; void map_ls_get_filename (char *fn, int len, int ilon, int ilat) { int flon, flat; flon = ilon/MAP_LSHASHFACTOR; flat = ilat/MAP_LSHASHFACTOR; #ifdef HAVE_LOCALE_H setlocale(LC_ALL, "C"); snprintf (fn, len, "%smlon%dlat%d.mapdata", cfg.mappath, flon, flat); setlocale(LC_ALL, NULL); #else snprintf (fn, len, "%smlon%dlat%d.mapdata", cfg.mappath, flon, flat); #endif }; /****************************************************************** * fine the stats inside the hash block, if not just load the file * into the memory. */ struct map_lsstat *map_ls_statget (char *fname) { int i, j; struct map_lsstat *mlssptr = NULL; struct map_lsstat mlss; /* check inside the mlsstat block */ for (i = 0; i < MAP_LSSTAT_MAX; i++) { if (strncmp (fname, mlsstat[i].fname, LEN_FILENAME) == 0) { /* found in list, push it to the first entry, free whats left */ if (i > 0) { mlss = mlsstat[i]; for (j = i; j > 0; j--) mlsstat[j] = mlsstat[j-1]; mlsstat[0] = mlss; } mlssptr = mlsstat; break; } } /* if not, load file from disk */ if (mlssptr == NULL) { mlssptr = map_ls_statopen (fname); /* free last element in mlsstat */ if (mlsstat[MAP_LSSTAT_MAX-1].fname[0] != '\0') map_ls_statclose (&mlsstat[MAP_LSSTAT_MAX-1]); /* push to the first entry */ for (j = MAP_LSSTAT_MAX-1; j > 0; j--) mlsstat[j] = mlsstat[j-1]; mlsstat[0] = *mlssptr; mlssptr = mlsstat; } return mlssptr; }; /****************************************************************** * check if we have enought free data in rw_data buffer */ void map_ls_rwdatacheck (int size) { char *old; if (lsrw_data == NULL) { lsrw_data_size = size; lsrw_data = ml_malloc (lsrw_data_size); ml_addinfo (lsrw_data, "lsrw_data"); } else if (lsrw_data_size < size) { old = lsrw_data; ml_addinfo (old, "old lsrw_data"); lsrw_data = ml_malloc (size); ml_addinfo (old, "lsrw_data new"); if (old) memcpy (lsrw_data, old, lsrw_data_size); lsrw_data_size = size; ml_free (old); } else if (size == 0) { ml_free (lsrw_data); lsrw_data = NULL; lsrw_data_size = 0; } }; void map_ls_rwdatacheckpos (int size, char **oldpos) { int i; i = *oldpos-lsrw_data; map_ls_rwdatacheck (size); *oldpos = lsrw_data+i; }; void map_ls_hashdatacheck (int size) { char *old; if (lshash_data == NULL) { lshash_data_size = size; lshash_data = ml_malloc (lshash_data_size); ml_addinfo (lshash_data, "lshash_data"); } else if (lshash_data_size < size) { old = lshash_data; ml_addinfo (old, "old lshash_data"); lshash_data = ml_malloc (size); ml_addinfo (lshash_data, "lshash_data new"); if (old) memcpy (lshash_data, old, lshash_data_size); lshash_data_size = size; ml_free (old); } }; void map_ls_hashdatacheckpos (int size, char **oldpos) { int i; i = *oldpos-lshash_data; map_ls_hashdatacheck (size); *oldpos = lshash_data+i; }; /********************************************************************* * try to open a map file, load imortant data into the mlss structure * and return it */ struct map_lsstat *map_ls_statopen (char *fname) { static struct map_lsstat mlss; int i; char *pos; map_ls_rwdatacheck (12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); /* clear mlss */ strncpy (mlss.fname, fname, LEN_FILENAME); mlss.fnametmp[0] = '\0'; for (i = 0; i < MAP_LSHASHFACTOR*MAP_LSHASHFACTOR; i++) { mlss.r_lshpos[i].pos = 0; mlss.r_lshpos[i].size = 0; mlss.w_lshpos[i].pos = 0; mlss.w_lshpos[i].size = 0; if (i < MAP_LSFREECNT) { mlss.w_free[i].pos = 0; mlss.w_free[i].size = 0; } } mlss.r_fd = mlss.w_fd = 0; mlss.changed = 0; if (file_exist (mlss.fname) == NULL) { d_printf ("map_ls_statopen file '%s' not found.", mlss.fname); mlss.r_fd = 0; return &mlss; } #if defined(__MINGW32CE__) || defined(_WIN32_WCE) || defined(__MINGW32__) mlss.r_fd = open (mlss.fname, O_RDWR | _O_BINARY); if (mlss.r_fd == -1) { int error = GetLastError(); d_printf ("map_ls_statopen open file '%s'. ERROR (GetLastError): %d", mlss.fname, error); mlss.r_fd = 0; return &mlss; } #else mlss.r_fd = open (mlss.fname, O_RDWR); if (mlss.r_fd == -1) { d_printf ("map_ls_statopen open file '%s'. ERROR (errno): %d:%s", mlss.fname, errno, strerror(errno)); mlss.r_fd = 0; return &mlss; } #endif // else d_printf ("map_ls_statopen open file '%s'. OK fd:%d", mlss.fname, mlss.r_fd); read (mlss.r_fd, lsrw_data, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); pos = lsrw_data; for (i = 0; i < MAP_LSHASHFACTOR*MAP_LSHASHFACTOR; i++) { pos = mempop (pos, &mlss.r_lshpos[i].pos, 8); pos = mempop (pos, &mlss.r_lshpos[i].size, 4); } for (i = 0; i < MAP_LSFREECNT; i++) { pos = mempop (pos, &mlss.w_free[i].pos, 8); pos = mempop (pos, &mlss.w_free[i].size, 4); } return &mlss; }; /********************************************************************* * close the read and write file but save first the w_free, r_lshpos * and the w_lshpos arrays */ void map_ls_statclose (struct map_lsstat *lsstat) { char *pos; int i; // d_printf ("map_ls_statclose called with: %p changed: %d r_fd: %d w_fd: %d", lsstat, lsstat->changed, lsstat->r_fd, lsstat->w_fd); if (lsstat->r_fd) { if (lsstat->changed) { map_ls_rwdatacheck (12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); /* data changed so need to save, all filenames should be right * so we only take care about r_fd and w_fd */ if (lsstat->w_fd == 0) { pos = lsrw_data; for (i = 0; i < MAP_LSHASHFACTOR*MAP_LSHASHFACTOR; i++) { pos = mempush (pos, &lsstat->r_lshpos[i].pos, 8); pos = mempush (pos, &lsstat->r_lshpos[i].size, 4); } for (i = 0; i < MAP_LSFREECNT; i++) { pos = mempush (pos, &lsstat->w_free[i].pos, 8); pos = mempush (pos, &lsstat->w_free[i].size, 4); } if (lseek (lsstat->r_fd, 0, SEEK_SET) < 0) d_printf ("%s:%d error with lseek.", __FILE__, __LINE__); write (lsstat->r_fd, lsrw_data, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); } else { /* need to copy all unchanged data into the new file */ for (i = 0; i < MAP_LSHASHFACTOR*MAP_LSHASHFACTOR; i++) { if (lsstat->w_lshpos[i].pos == 0 && lsstat->r_lshpos[i].pos != 0) { /* read data */ map_ls_rwdatacheck (lsstat->r_lshpos[i].size); if (lseek (lsstat->r_fd, lsstat->r_lshpos[i].pos, SEEK_SET) < 0) d_printf ("%s:%d error with lseek.", __FILE__, __LINE__); read (lsstat->r_fd, lsrw_data, lsstat->r_lshpos[i].size); /* write data */ if ((lsstat->w_lshpos[i].pos = lseek (lsstat->w_fd, 0, SEEK_END)) < 0) d_printf ("%s:%d error with lseek.", __FILE__, __LINE__); lsstat->w_lshpos[i].size = lsstat->r_lshpos[i].size; write (lsstat->w_fd, lsrw_data, lsstat->w_lshpos[i].size); } } pos = lsrw_data; for (i = 0; i < MAP_LSHASHFACTOR*MAP_LSHASHFACTOR; i++) { pos = mempush (pos, &lsstat->w_lshpos[i].pos, 8); pos = mempush (pos, &lsstat->w_lshpos[i].size, 4); } for (i = 0; i < MAP_LSFREECNT; i++) { pos = mempush (pos, &lsstat->w_free[i].pos, 8); pos = mempush (pos, &lsstat->w_free[i].size, 4); } if (lseek (lsstat->w_fd, 0, SEEK_SET) < 0) d_printf ("%s:%d error with lseek.", __FILE__, __LINE__); write (lsstat->w_fd, lsrw_data, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); } } close (lsstat->r_fd); // d_printf ("map_ls_statclose close file r_fd:%d", lsstat->r_fd); if (lsstat->w_fd) { close (lsstat->w_fd); // d_printf ("map_ls_statclose close file w_fd:%d", lsstat->w_fd); unlink (lsstat->fnametmp); } } lsstat->fname[0] = '\0'; lsstat->fnametmp[0] = '\0'; lsstat->r_fd = 0; lsstat->w_fd = 0; }; /********************************************************* * load the data, do not convert them yet.. but check * if we need to load the data from r_fd or w_fd */ char *map_ls_loaddata (struct map_lsstat *lsstat, int *size, int ilon, int ilat) { int flon = ilon - (ilon/MAP_LSHASHFACTOR)*MAP_LSHASHFACTOR; int flat = ilat - (ilat/MAP_LSHASHFACTOR)*MAP_LSHASHFACTOR; int nr = flon * MAP_LSHASHFACTOR + flat; int fd; uint64_t pos; if (nr < 0 || nr >= MAP_LSHASHFACTOR*MAP_LSHASHFACTOR) { d_printf ("WARN: map_ls_loaddata nr[%d] > MAP_LSHASHFACTOR^2[%d] ipos:%d,%d", nr, MAP_LSHASHFACTOR*MAP_LSHASHFACTOR, ilon, ilat); return NULL; } if (lsstat->r_fd == 0) return NULL; if (lsstat->w_fd > 0 && lsstat->w_lshpos[nr].pos != 0) { /* w_fd has data? */ fd = lsstat->w_fd; pos = lsstat->w_lshpos[nr].pos; *size = lsstat->w_lshpos[nr].size; } else if (lsstat->r_lshpos[nr].pos != 0) { /* r_fd has data ? */ fd = lsstat->r_fd; pos = lsstat->r_lshpos[nr].pos; *size = lsstat->r_lshpos[nr].size; } else { return NULL; } /* read the data */ map_ls_hashdatacheck (*size); if (lseek (fd, pos, SEEK_SET) < 0) d_printf ("%s:%d error with lseek.", __FILE__, __LINE__); if (read (fd, lshash_data, *size) != *size) { d_printf ("ERROR: map_ls_loaddata: ERROR hashdata could not been loaded."); d_printf (" lsstat fname:%s fnametmp:%s r_fd:%d, w_fd:%d", lsstat->fname, lsstat->fnametmp, lsstat->r_fd, lsstat->w_fd); d_printf (" fd:%d pos:%lld size:%d", fd, pos, *size); errorexit (1); } return lshash_data; }; void map_ls_savedata (struct map_lsstat *lsstat, char *data, int size, int ilon, int ilat) { int flon = ilon - (ilon/MAP_LSHASHFACTOR)*MAP_LSHASHFACTOR; int flat = ilat - (ilat/MAP_LSHASHFACTOR)*MAP_LSHASHFACTOR; int nr = flon * MAP_LSHASHFACTOR + flat; int fd, i; uint64_t pos; struct map_lshmap olddatapos = {0, 0}; if (nr < 0 || nr >= MAP_LSHASHFACTOR*MAP_LSHASHFACTOR) { d_printf ("WARN: map_ls_savedata nr[%d] > MAP_LSHASHFACTOR^2[%d] ipos:%d,%d", nr, MAP_LSHASHFACTOR*MAP_LSHASHFACTOR, ilon, ilat); return; } if (lsstat->r_fd == 0) { /* open new file and write empty data in it*/ map_ls_rwdatacheck (12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); memset (lsrw_data, 0x0, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); #if defined(__MINGW32CE__) || defined(_WIN32_WCE) || defined(__MINGW32__) fd = open (lsstat->fname, O_CREAT|O_RDWR|O_TRUNC|_O_BINARY, 0644); #else fd = open (lsstat->fname, O_CREAT|O_RDWR|O_TRUNC, 0644); #endif if (fd == -1) { /* Error... so free all unneeded memory */ d_printf ("ERROR: map_ls_savedata could not open file [%s]for writing.\n", lsstat->fname); errorexit (-1); } // else d_printf ("map_ls_savedata open file %s fd:%d", lsstat->fname, fd); write (fd, lsrw_data, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); } else if (lsstat->w_fd > 0) { /* new write file already opened? * use new write file */ fd = lsstat->w_fd; olddatapos = lsstat->w_lshpos[nr]; } else if (lsstat->r_lshpos[nr].pos != 0) { /* defrag of readfile still below 50% use read file else, * open new write file */ fd = lsstat->r_fd; pos = lseek (lsstat->r_fd, 0, SEEK_END); if (pos < 0) d_printf ("%s:%d error with lseek.", __FILE__, __LINE__); else if (lsstat->w_free[0].size > pos || lsstat->w_free[0].pos >= (MAP_LSFREECNT-2)) { /* * got over 25% lost already or maximum of free fields reached */ d_printf (" maximum of free blocks reached. cnt:%lld size:%d bytes, file:%s", lsstat->w_free[0].pos, lsstat->w_free[0].size, lsstat->fname); close (lsstat->r_fd); d_printf ("map_ls_savedata close file fd: %d", lsstat->r_fd); snprintf (lsstat->fnametmp, LEN_FILENAME, "%s.tmp", lsstat->fname); if (rename (lsstat->fname, lsstat->fnametmp) != 0) { d_printf ("ERROR: map_ls_savedata rename(%s,%s) failed: %s", lsstat->fname, lsstat->fnametmp, strerror(errno)); errorexit (1); } /* open new file and write empty data in it*/ map_ls_rwdatacheck (12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); memset (lsrw_data, 0x0, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); lsstat->w_fd = open (lsstat->fname, O_CREAT|O_RDWR|O_TRUNC, 0644); if (lsstat->w_fd <= 0) { /* Error... so free all unneeded memory */ d_printf ("ERROR: map_ls_savedata could not open file [%s]for writing: ", lsstat->fname, strerror(errno)); errorexit (-1); } // else d_printf ("map_ls_savedata open file %s w_fd:%d", lsstat->fname, lsstat->w_fd); write (lsstat->w_fd, lsrw_data, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); /* fill in new structure */ for (i = 0; i < MAP_LSHASHFACTOR*MAP_LSHASHFACTOR; i++) { lsstat->w_lshpos[i].pos = 0; lsstat->w_lshpos[i].size = 0; if (i < MAP_LSFREECNT) { lsstat->w_free[i].pos = 0; lsstat->w_free[i].size = 0; } } /* reopen old file for reading */ #if defined(__MINGW32CE__) || defined(_WIN32_WCE) || defined(__MINGW32__) lsstat->r_fd = open (lsstat->fnametmp, O_RDONLY | _O_BINARY); #else lsstat->r_fd = open (lsstat->fnametmp, O_RDONLY); #endif if (lsstat->r_fd <= 0) { /* Error... so free all unneeded memory */ d_printf ("ERROR: map_ls_savedata could not open file [%s] for reading: ", lsstat->fnametmp, strerror(errno)); errorexit (-1); } fd = lsstat->w_fd; olddatapos = lsstat->w_lshpos[nr]; } else { olddatapos = lsstat->r_lshpos[nr]; } } else { fd = lsstat->r_fd; olddatapos = lsstat->r_lshpos[nr]; } /* * write datablock, and mark */ if ((pos = lseek (fd, 0, SEEK_END)) < 0) d_printf ("%s:%d error with lseek.", __FILE__, __LINE__); if ((i = write (fd, data, size)) < size) { d_printf ("ERROR: map_ls_savedata written bytes are not as many as requested. i:%d size:%d error:%s", i, size, strerror (errno)); errorexit (1); } /* * mark data as free */ if (olddatapos.pos > 0) { lsstat->w_free[lsstat->w_free[0].pos+1] = olddatapos; lsstat->w_free[0].pos++; lsstat->w_free[0].size = lsstat->w_free[0].size +olddatapos.size; } /* * setup fd and r_fd and w_fd */ if (lsstat->r_fd == 0) lsstat->r_fd = fd; if (fd == lsstat->r_fd) { lsstat->w_fd = 0; lsstat->r_lshpos[nr].pos = pos; lsstat->r_lshpos[nr].size = size; } else { lsstat->w_fd = fd; lsstat->w_lshpos[nr].pos = pos; lsstat->w_lshpos[nr].size = size; } lsstat->changed = 1; /* if we have already alot unused data inside the * w_fd close it, so we can later on create a new file */ if (lsstat->w_fd >0 && lsstat->w_free[0].pos >= MAP_LSFREECNT/2) map_ls_statclose (lsstat); }; /************************************************************ * convert hash to datablock and return also it's size */ char *map_ls_hash2data (struct map_hash *mh, int *size) { struct map_way *mw; struct map_area *ma; struct map_place *mp; struct map_poi *mpoi; struct map_lshentry lsh; int obj_cnt, j, cur_size; char *woutpos = NULL; uint64_t ui64; /* datatypes needed for convert */ uint32_t ui32; uint16_t ui16; uint8_t ui8; /* * write ways */ *size = MAP_LSSIZE_HASH; lsh.ways = 0; lsh.areas = 0; lsh.pois = 0; lsh.places = 0; lsh.ncnt = 0; lsh.pcnt = 0; lsh.ccnt = 0; map_ls_hashdatacheck (*size); woutpos = lshash_data+MAP_LSSIZE_HASH; /* the end of lshentry */ mw = mh->ways; obj_cnt = 0; while (mw && obj_cnt < mh->wayscnt) { obj_cnt++; if (mw != NULL) { /* check if the allocated memory is enought */ cur_size = 2; if (mw->name) cur_size += strlen (mw->name); if (mw->ref) cur_size += strlen (mw->ref); lsh.ccnt += cur_size; *size = *size + MAP_LSSIZE_WAY + mw->p_cnt * MAP_LSSIZE_POS + mw->n_cnt * MAP_LSSIZE_WAYNODE + cur_size; map_ls_hashdatacheckpos (*size, &woutpos); /* save the basic data */ ui64 = mw->id; /* id */ ui64 = (ui64 << MAP_BITS_SUBID) | mw->subid; woutpos = mempush (woutpos, &ui64, 8); ui8 = mw->type; /* type */ woutpos = mempush (woutpos, &ui8, 1); ui8 = mw->flags; /* flags */ woutpos = mempush (woutpos, &ui8, 1); /* name */ ui8 = 0x0; if (mw->name) woutpos = mempush (woutpos, mw->name, strlen (mw->name)+1); else woutpos = mempush (woutpos, &ui8, 1); /* ref */ if (mw->ref) woutpos = mempush (woutpos, mw->ref, strlen (mw->ref)+1); else woutpos = mempush (woutpos, &ui8, 1); ui16 = mw->n_cnt; /* n_cnt */ woutpos = mempush (woutpos, &ui16, 2); ui16 = mw->p_cnt; /* p_cnt */ woutpos = mempush (woutpos, &ui16, 2); /* save the waynodes */ for (j = 0; j < mw->n_cnt; j++) { woutpos = mempush (woutpos, &mw->n[j].d.lon, 4); woutpos = mempush (woutpos, &mw->n[j].d.lat, 4); ui64 = mw->n[j].d_id; woutpos = mempush (woutpos, &ui64, 8); ui16 = mw->n[j].d_subid; woutpos = mempush (woutpos, &ui16, 2); ui16 = mw->n[j].d_pnr; woutpos = mempush (woutpos, &ui16, 2); ui16 = mw->n[j].pnr; woutpos = mempush (woutpos, &ui16, 2); ui8 = mw->n[j].flags; woutpos = mempush (woutpos, &ui8, 1); lsh.ncnt++; } /* save the points */ for (j = 0; j < mw->p_cnt; j++) { woutpos = mempush (woutpos, &mw->p[j].lon, 4); woutpos = mempush (woutpos, &mw->p[j].lat, 4); lsh.pcnt++; } /* write the way on disk and increase ways counter */ lsh.ways++; // add the next way } mw = mw->next; } if (mw) d_printf ("%s:%d map_save_hash all ways saved but mw != NULL (%p)", __FILE__, __LINE__, mw); /* * write the areas */ ma = mh->areas; obj_cnt = 0; while (ma && obj_cnt < mh->areascnt) { obj_cnt++; if (ma != NULL) { /* check if the allocated memory is enought */ *size = *size + MAP_LSSIZE_AREA + ma->p_cnt * MAP_LSSIZE_POS; map_ls_hashdatacheckpos (*size, &woutpos); /* save the basic data */ ui64 = (ma->id << MAP_BITS_SUBID) | ma->subid; /* id */ woutpos = mempush (woutpos, &ui64, 8); ui8 = ma->type; /* type */ woutpos = mempush (woutpos, &ui8, 1); ui8 = ma->flags; /* flags */ woutpos = mempush (woutpos, &ui8, 1); ui16 = ma->p_cnt; /* p_cnt */ woutpos = mempush (woutpos, &ui16, 2); /* save the points */ for (j = 0; j < ma->p_cnt; j++) { woutpos = mempush (woutpos, &ma->p[j].lon, 4); woutpos = mempush (woutpos, &ma->p[j].lat, 4); lsh.pcnt++; } /* write the way on disk and increase ways counter */ lsh.areas++; // add the next way } ma = ma->next; } if (ma) d_printf ("%s:%d map_save_hash all areas saved but ma != NULL (%p)", __FILE__, __LINE__, ma); /* * save place data */ mp = mh->places; obj_cnt = 0; while (mp && obj_cnt < mh->placescnt) { obj_cnt++; if (mp != NULL) { /* check if the allocated memory is enought */ cur_size = 5; if (mp->country) cur_size += strlen (mp->country); if (mp->state) cur_size += strlen (mp->state); if (mp->district) cur_size += strlen (mp->district); if (mp->name) cur_size += strlen (mp->name); if (mp->postalcode) cur_size += strlen (mp->postalcode); lsh.ccnt += cur_size; *size = *size + cur_size + MAP_LSSIZE_PLACE; map_ls_hashdatacheckpos (*size, &woutpos); /* save the basic data */ woutpos = mempush (woutpos, &mp->lon, 4); woutpos = mempush (woutpos, &mp->lat, 4); ui64 = mp->id; /* id */ woutpos = mempush (woutpos, &ui64, 8); ui8 = mp->type; /* type */ woutpos = mempush (woutpos, &ui8, 1); ui32 = mp->population; /* population */ woutpos = mempush (woutpos, &ui32, 4); /* save the text */ ui8 = 0x0; /* country */ if (mp->country) woutpos = mempush (woutpos, mp->country, strlen (mp->country)+1); else woutpos = mempush (woutpos, &ui8, 1); /* state */ if (mp->state) woutpos = mempush (woutpos, mp->state, strlen (mp->state)+1); else woutpos = mempush (woutpos, &ui8, 1); /* district */ if (mp->district) woutpos = mempush (woutpos, mp->district, strlen (mp->district)+1); else woutpos = mempush (woutpos, &ui8, 1); /* name */ if (mp->name) woutpos = mempush (woutpos, mp->name, strlen (mp->name)+1); else woutpos = mempush (woutpos, &ui8, 1); /* postalcode */ if (mp->postalcode) woutpos = mempush (woutpos, mp->postalcode, strlen (mp->postalcode)+1); else woutpos = mempush (woutpos, &ui8, 1); lsh.places++; // add the next way } mp = mp->next; } if (mp) d_printf ("%s:%d map_save_hash all places saved but mp != NULL (%p)", __FILE__, __LINE__, mp); /* * save poi data */ mpoi = mh->pois; obj_cnt = 0; while (mpoi && obj_cnt < mh->poiscnt) { obj_cnt++; if (mpoi != NULL) { /* check if the allocated memory is enought */ cur_size = 2; if (mpoi->name) cur_size += strlen (mpoi->name); if (mpoi->additional) cur_size += strlen (mpoi->additional); lsh.ccnt += cur_size; *size = *size + cur_size + MAP_LSSIZE_POI; map_ls_hashdatacheckpos (*size, &woutpos); /* save the basic data */ woutpos = mempush (woutpos, &mpoi->lon, 4); woutpos = mempush (woutpos, &mpoi->lat, 4); ui64 = mpoi->id; /* id */ woutpos = mempush (woutpos, &ui64, 8); ui8 = mpoi->type; /* type */ woutpos = mempush (woutpos, &ui8, 1); /* save the text */ ui8 = 0x0; /* name */ if (mpoi->name) woutpos = mempush (woutpos, mpoi->name, strlen (mpoi->name)+1); else woutpos = mempush (woutpos, &ui8, 1); /* additional */ if (mpoi->additional) woutpos = mempush (woutpos, mpoi->additional, strlen (mpoi->additional)+1); else woutpos = mempush (woutpos, &ui8, 1); lsh.pois++; // add the next poi } mpoi = mpoi->next; } if (mpoi) d_printf ("%s:%d map_save_hash all pois saved but mpoi != NULL (%p)", __FILE__, __LINE__, mpoi); /* setup the lsh into the file */ woutpos = lshash_data; ui32 = lsh.ways; woutpos = mempush (woutpos, &ui32, 4); ui32 = lsh.areas; woutpos = mempush (woutpos, &ui32, 4); ui32 = lsh.pois; woutpos = mempush (woutpos, &ui32, 4); ui32 = lsh.places; woutpos = mempush (woutpos, &ui32, 4); ui32 = lsh.ncnt; woutpos = mempush (woutpos, &ui32, 4); ui32 = lsh.pcnt; woutpos = mempush (woutpos, &ui32, 4); ui32 = lsh.ccnt; woutpos = mempush (woutpos, &ui32, 4); return lshash_data; }; /******************************************************************* * convert data into hash */ struct map_hash *map_ls_data2hash (char *data, int size) { struct map_lshentry lsh; struct map_hash *mh = NULL; struct map_way *way = NULL; struct map_area *area = NULL; struct map_place *place = NULL; struct map_poi *poi = NULL; char *inpos; int i, cnt; uint64_t ui64; /* datatypes needed for convert */ uint32_t ui32; uint16_t ui16; uint8_t ui8; inpos = data; inpos = mempop (inpos, &ui32, 4); lsh.ways = ui32; inpos = mempop (inpos, &ui32, 4); lsh.areas = ui32; inpos = mempop (inpos, &ui32, 4); lsh.pois = ui32; inpos = mempop (inpos, &ui32, 4); lsh.places = ui32; inpos = mempop (inpos, &ui32, 4); lsh.ncnt = ui32; inpos = mempop (inpos, &ui32, 4); lsh.pcnt = ui32; inpos = mempop (inpos, &ui32, 4); lsh.ccnt = ui32; mh = map_hash_alloc (map_hash_calc_size (lsh.ways, lsh.areas, lsh.pois, lsh.places, lsh.pcnt, lsh.ncnt, lsh.ccnt)); mh->wayscnt = lsh.ways; mh->areascnt = lsh.areas; mh->poiscnt = lsh.pois; mh->placescnt = lsh.places; if (lsh.ways > 0) { /* * prepare and read the way */ way = (struct map_way*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); mh->ways = way; mh->wayscnt = lsh.ways; /* read all ways */ for (cnt = 0; cnt < lsh.ways; cnt++) { /* load basic data */ inpos = mempop (inpos, &ui64, 8); way->subid = ui64 % (1<id = (ui64 >> MAP_BITS_SUBID); inpos = mempop (inpos, &ui8, 1); way->type = ui8; inpos = mempop (inpos, &ui8, 1); way->flags = ui8; inpos = memstrpop (inpos, way->name, &i); if (i >= MAP_W_NAMELEN) { static int _only_once_ = 1; if (_only_once_) d_printf ("%s:%d ERROR in %s: i(%d) > MAP_W_NAMELEN(%d). Name:'%s'", __FILE__, __LINE__, __FUNCTION__, i, MAP_W_NAMELEN, way->name); _only_once_ = 0; i = MAP_W_NAMELEN - 1; } way->name[i] = 0; inpos = memstrpop (inpos, way->ref, &i); if (i >= MAP_W_NAMELEN) { static int _only_once_ = 1; if (_only_once_) d_printf ("%s:%d ERROR in %s: i(%d) > MAP_W_NAMELEN(%d). Ref:'%s'", __FILE__, __LINE__, __FUNCTION__, i, MAP_W_NAMELEN, way->ref); _only_once_ = 0; i = MAP_W_NAMELEN - 1; } way->ref[i] = 0; inpos = mempop (inpos, &ui16, 2); way->n_cnt = ui16; inpos = mempop (inpos, &ui16, 2); way->p_cnt = ui16; /* save the waynodes */ way->n = (struct map_waynode*)way->data; for (i = 0; i < way->n_cnt; i++) { inpos = mempop (inpos, &way->n[i].d.lon, 4); inpos = mempop (inpos, &way->n[i].d.lat, 4); inpos = mempop (inpos, &ui64, 8); way->n[i].d_id = ui64; inpos = mempop (inpos, &ui16, 2); way->n[i].d_subid = ui16; inpos = mempop (inpos, &ui16, 2); way->n[i].d_pnr = ui16; inpos = mempop (inpos, &ui16, 2); way->n[i].pnr = ui16; inpos = mempop (inpos, &ui8, 1); way->n[i].flags = ui8; } /* save the points */ way->p = (struct map_pos*) (way->data + (way->n_cnt * sizeof (struct map_waynode))); for (i = 0; i < way->p_cnt; i++) { inpos = mempop (inpos, &way->p[i].lon, 4); inpos = mempop (inpos, &way->p[i].lat, 4); } mh->free = mh->free + map_way_getsize (way); if (cnt < (lsh.ways-1)) way->next = (struct map_way*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); else way->next = NULL; way = (struct map_way*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); } } /* * prepare to read the areas */ if (lsh.areas > 0) { area = (struct map_area*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); mh->areascnt = lsh.areas; mh->areas = area; area->prev = NULL; /* read all area */ for (cnt = 0; cnt < lsh.areas; cnt++) { /* load and setup basic data */ area->next = NULL; inpos = mempop (inpos, &ui64, 8); area->subid = ui64 % (1<id = ui64; inpos = mempop (inpos, &ui8, 1); area->type = ui8; inpos = mempop (inpos, &ui8, 1); area->flags = ui8; inpos = mempop (inpos, &ui16, 2); area->p_cnt = ui16; /* read the points */ area->p = (struct map_pos*) area->data; for (i = 0; i < area->p_cnt; i++) { inpos = mempop (inpos, &area->p[i].lon, 4); inpos = mempop (inpos, &area->p[i].lat, 4); } mh->free = mh->free + map_area_getsize (area); /* * check if we are still in order */ while (area->prev != NULL && area->type < area->prev->type) { struct map_area *parea = area->prev; /* nighbours pointers change */ if (parea->prev == NULL) mh->areas = area; else parea->prev->next = area; if (area->next != NULL) area->next->prev = parea; /* swap area->prev with area */ parea->next = area->next; area->prev = parea->prev; parea->prev = area; area->next = parea; /* check next */ area = parea; } for (;area->next != NULL; area = area->next); if (cnt < (lsh.areas-1)) { area->next = (struct map_area*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); area->next->prev = area; area = area->next; } else area->next = NULL; } } /* * prepare to read places */ if (lsh.places > 0) { place = (struct map_place*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); mh->placescnt = lsh.places; mh->places = place; /* read all area */ for (cnt = 0; (cnt < lsh.places); cnt++) { /* load basic data */ inpos = mempop (inpos, &place->lon, 4); inpos = mempop (inpos, &place->lat, 4); inpos = mempop (inpos, &ui64, 8); place->id = ui64; inpos = mempop (inpos, &ui8, 1); place->type = ui8; inpos = mempop (inpos, &ui32, 4); place->population = ui32; /* read the text data */ place->country = place->data; inpos = memstrpop (inpos, place->country, &i); place->state = place->country+i; inpos = memstrpop (inpos, place->state, &i); place->district = place->state+i; inpos = memstrpop (inpos, place->district, &i); place->name = place->district+i; inpos = memstrpop (inpos, place->name, &i); place->postalcode = place->name+i; inpos = memstrpop (inpos, place->postalcode, &i); mh->free = mh->free + map_place_getsize (place); if (cnt < (lsh.places-1)) place->next = (struct map_place*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); else place->next = NULL; place = (struct map_place*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); } } /* * prepare to read pois */ if (lsh.pois > 0) { poi = (struct map_poi*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); mh->poiscnt = lsh.pois; mh->pois = poi; /* read all area */ for (cnt = 0; (cnt < lsh.pois); cnt++) { /* load basic data */ inpos = mempop (inpos, &poi->lon, 4); inpos = mempop (inpos, &poi->lat, 4); inpos = mempop (inpos, &ui64, 8); poi->id = ui64; inpos = mempop (inpos, &ui8, 1); poi->type = ui8; /* read the text data */ poi->name = poi->data; inpos = memstrpop (inpos, poi->name, &i); poi->additional = poi->name+i; inpos = memstrpop (inpos, poi->additional, &i); mh->free = mh->free + map_poi_getsize (poi); if (cnt < (lsh.pois-1)) poi->next = (struct map_poi*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); else poi->next = NULL; poi = (struct map_poi*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); } } mh->pos.ilon = 0; mh->pos.ilat = 0; if ((char*)mh->free - (char*)mh > mh->datasize) { d_printf ("ERROR: map_ls_data2hash buffer overrun! memsize:%d < mh->free-mh:%d", mh->datasize, (char*)mh->free - (char*)mh); errorexit(1); } DELFLAG(mh->status, MS_changed); return mh; }; /**************************************************************** * load hash data */ struct map_hash *map_load_hash (int ilon, int ilat) { char fn[LEN_FILENAME]; struct map_lsstat *mlss = NULL; char *data; int size; struct map_hash *mh; map_ls_get_filename (fn, LEN_FILENAME, ilon, ilat); mlss = map_ls_statget (fn); if (mlss == NULL) { d_printf ("WARN: map_load_hash no pointer to mlss structure (fn:%s igeo:%d,%d)", fn, ilon, ilat); return NULL; } data = map_ls_loaddata (mlss, &size, ilon, ilat); if (data == NULL) { return NULL; } mh = map_ls_data2hash (data, size); if (mh) { mh->pos.ilon = ilon; mh->pos.ilat = ilat; } return mh; }; int map_save_hash (struct map_hash *mh) { char fn[LEN_FILENAME]; struct map_lsstat *mlss = NULL; char *data; int size = 0; if (ISNOTFLAG(mh->status, MS_changed)) return 0; map_ls_get_filename (fn, LEN_FILENAME, mh->pos.ilon, mh->pos.ilat); mlss = map_ls_statget (fn); if (mlss == NULL) { d_printf ("WARN: map_save_hash no pointer to mlss structure (fn:%s igeo:%d,%d)", fn, mh->pos.ilon, mh->pos.ilat); return 0; } data = map_ls_hash2data (mh, &size); map_ls_savedata (mlss, data, size, mh->pos.ilon, mh->pos.ilat); DELFLAG(mh->status, MS_changed); return 1; }; void map_save_all () { int i = 0; while (i < mhash_max) for (i = 0; i < mhash_max; i++) { if (mhash[i]) if (ISFLAG(mhash[i]->status, MS_changed)) { if (mhash[i] != map_hash_geti (mhash[i]->pos.ilon , mhash[i]->pos.ilat, MHLOAD_NONE)) d_printf ("%s:%d something went wrong mhash != map_hash_get",__FILE__,__LINE__); if (map_save_hash (mhash[i]) == 0) DELFLAG(mhash[i]->status, MS_changed); break; } main_wnd_update (); } for (i = 0; i < MAP_LSSTAT_MAX; i++) { if (mlsstat[i].fname[0] != '\0') map_ls_statclose (&mlsstat[i]); } }; /**************************************************************************** * defrag the map data files, needed to decrease the size of the file. */ void map_defrag () { DIR *directory = NULL; struct dirent *direntry = NULL; static struct stat filestat; char fn[LEN_FILENAME]; d_printf ("map_defrag"); directory = opendir(cfg.mappath); if (directory == NULL) { d_printf ("map_defrag opendir (%s) failed:%s", cfg.mappath, strerror (errno)); return; } while ((direntry = readdir (directory)) != NULL) { snprintf (fn, LEN_FILENAME, "%s/%s", cfg.mappath, direntry->d_name); if (strncmp ((direntry->d_name+strlen(direntry->d_name)-8), ".mapdata", 9) == 0 && stat(fn, &filestat) == 0) if (S_ISREG(filestat.st_mode)) { d_printf ("defrag file:%s size:%ld", direntry->d_name, filestat.st_size); map_defragfile (fn); stat(fn, &filestat); d_printf (" now:%s size:%ld", direntry->d_name, filestat.st_size); } } closedir (directory); }; void map_defragfile (char *fn) { struct map_lsstat *lsstat = NULL; int i; /* get lsstat from old file */ map_clear(); lsstat = map_ls_statopen (fn); d_printf ("lsstat r_fd:%d, w_fd:%d", lsstat->r_fd, lsstat->w_fd); /* reopen file and create write file */ close (lsstat->r_fd); d_printf ("map_defragfile close file r_fd:%d", lsstat->r_fd); snprintf (lsstat->fnametmp, LEN_FILENAME, "%s.tmp", lsstat->fname); if (rename (lsstat->fname, lsstat->fnametmp) != 0) { d_printf ("ERROR: map_defragfile rename(%s,%s) failed: %s", lsstat->fname, lsstat->fnametmp, strerror(errno)); errorexit (1); } /* open new file and write empty data in it*/ map_ls_rwdatacheck (12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); memset (lsrw_data, 0x0, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); lsstat->w_fd = open (lsstat->fname, O_CREAT|O_RDWR|O_TRUNC, 0644); if (lsstat->w_fd <= 0) { /* Error... so quit */ d_printf ("ERROR: map_defrag could not open file [%s]for writing: ", lsstat->fname, strerror(errno)); errorexit (-1); } write (lsstat->w_fd, lsrw_data, 12*(MAP_LSHASHFACTOR*MAP_LSHASHFACTOR+MAP_LSFREECNT)); /* fill in new structure */ for (i = 0; i < MAP_LSHASHFACTOR*MAP_LSHASHFACTOR; i++) { lsstat->w_lshpos[i].pos = 0; lsstat->w_lshpos[i].size = 0; if (i < MAP_LSFREECNT) { lsstat->w_free[i].pos = 0; lsstat->w_free[i].size = 0; } } /* reopen old file for reading */ #if defined(__MINGW32CE__) || defined(_WIN32_WCE) || defined(__MINGW32__) lsstat->r_fd = open (lsstat->fnametmp, O_RDONLY | _O_BINARY); #else lsstat->r_fd = open (lsstat->fnametmp, O_RDONLY); #endif if (lsstat->r_fd <= 0) { /* Error... so free all unneeded memory */ d_printf ("ERROR: map_defrag could not open file [%s] for reading: ", lsstat->fnametmp, strerror(errno)); errorexit (-1); } else { d_printf ("map_defragfile open file %s r_fd:%d", lsstat->fnametmp, lsstat->r_fd); } lsstat->changed = 1; map_ls_statclose (lsstat); map_init (); };