You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
spOSMroute/mapsys/map_loadsave.c

1217 lines
35 KiB

/***************************************************************************
* 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 <locale.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include "map.h"
#include "system.h"
#include "memoryleak.h"
#include "osmroute.h"
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 */
woutpos = mempush (woutpos, &ui64, 8);
ui16 = mw->subid; /* subid */
woutpos = mempush (woutpos, &ui16, 2);
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; /* 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->id = ui64;
inpos = mempop (inpos, &ui16, 2);
way->subid = ui16;
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->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_loop (i, mhash_max);
}
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 ();
};