X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/228213c5672377407ec7822edeb2607189b9d441..c2cf03332f51a9fa992220124635f737399fba91:/src/dem.c diff --git a/src/dem.c b/src/dem.c index 488c061c..461c2bdf 100644 --- a/src/dem.c +++ b/src/dem.c @@ -1,17 +1,58 @@ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (C) 2003-2008, Evan Battaglia + * Copyright (C) 2007, Quy Tonthat + * + * 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_CONFIG_H +#include "config.h" +#endif + #include +#ifdef HAVE_STRING_H #include +#endif #include +#ifdef HAVE_MATH_H #include +#endif +#ifdef HAVE_STDLIB_H #include -#include +#endif #include #include +#ifdef HAVE_UNISTD_H #include -#include +#endif +#include +#include +#include "compression.h" #include "dem.h" -#include "file.h" +#include "coords.h" +#include "fileutils.h" + +/* Compatibility */ +#if ! GLIB_CHECK_VERSION(2,22,0) +#define g_mapped_file_unref g_mapped_file_free +#endif #define DEM_BLOCK_SIZE 1024 #define GET_COLUMN(dem,n) ((VikDEMColumn *)g_ptr_array_index( (dem)->columns, (n) )) @@ -22,7 +63,7 @@ static gboolean get_double_and_continue ( gchar **buffer, gdouble *tmp, gboolean *tmp = g_strtod(*buffer, &endptr); if ( endptr == NULL|| endptr == *buffer ) { if ( warn ) - g_warning("Invalid DEM"); + g_warning(_("Invalid DEM")); return FALSE; } *buffer=endptr; @@ -36,7 +77,7 @@ static gboolean get_int_and_continue ( gchar **buffer, gint *tmp, gboolean warn *tmp = strtol(*buffer, &endptr, 10); if ( endptr == NULL|| endptr == *buffer ) { if ( warn ) - g_warning("Invalid DEM"); + g_warning(_("Invalid DEM")); return FALSE; } *buffer=endptr; @@ -78,7 +119,7 @@ static gboolean dem_parse_header ( gchar *buffer, VikDEM *dem ) /* skip numbers 5-19 */ for ( i = 0; i < 15; i++ ) { if ( ! get_double_and_continue(&buffer, &val, FALSE) ) { - g_warning ("Invalid DEM header"); + g_warning (_("Invalid DEM header")); return FALSE; } } @@ -147,7 +188,7 @@ static void dem_parse_block_as_header ( gchar *buffer, VikDEM *dem, gint *cur_co /* 1 x n_rows 1 east_west south x x x DATA */ if ( (!get_double_and_continue(&buffer, &tmp, TRUE)) || tmp != 1 ) { - g_warning("Incorrect DEM Class B record: expected 1"); + g_warning(_("Incorrect DEM Class B record: expected 1")); return; } @@ -160,7 +201,7 @@ static void dem_parse_block_as_header ( gchar *buffer, VikDEM *dem, gint *cur_co n_rows = (guint) tmp; if ( (!get_double_and_continue(&buffer, &tmp, TRUE)) || tmp != 1 ) { - g_warning("Incorrect DEM Class B record: expected 1"); + g_warning(_("Incorrect DEM Class B record: expected 1")); return; } @@ -211,91 +252,19 @@ static void dem_parse_block ( gchar *buffer, VikDEM *dem, gint *cur_column, gint } } -/* return size of unzip data or 0 if failed */ -/* can be made generic to uncompress zip, gzip, bzip2 data */ -static guint uncompress_data(void *uncompressed_buffer, guint uncompressed_size, void *compressed_data, guint compressed_size) -{ - z_stream stream; - int err; - - stream.next_in = compressed_data; - stream.avail_in = compressed_size; - stream.next_out = uncompressed_buffer; - stream.avail_out = uncompressed_size; - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - /* negative windowBits to inflateInit2 means "no header" */ - if ((err = inflateInit2(&stream, -MAX_WBITS)) != Z_OK) { - g_warning("%s(): inflateInit2 failed", __PRETTY_FUNCTION__); - return 0; - } - - err = inflate(&stream, Z_FINISH); - if ((err != Z_OK) && (err != Z_STREAM_END) && stream.msg) { - g_warning("%s() inflate failed err=%d \"%s\"", __PRETTY_FUNCTION__, err, stream.msg == NULL ? "unknown" : stream.msg); - inflateEnd(&stream); - return 0; - } - - inflateEnd(&stream); - return(stream.total_out); -} - -static void *unzip_hgt_file(gchar *zip_file, gulong *unzip_size) -{ - void *unzip_data = NULL; - gchar *zip_data; - struct _lfh { - guint32 sig; - guint16 extract_version; - guint16 flags; - guint16 comp_method; - guint16 time; - guint16 date; - guint32 crc_32; - guint32 compressed_size; - guint32 uncompressed_size; - guint16 filename_len; - guint16 extra_field_len; - } __attribute__ ((__packed__)) *local_file_header = NULL; - - - local_file_header = (struct _lfh *) zip_file; - if (local_file_header->sig != 0x04034b50) { - g_warning("%s(): wrong format\n", __PRETTY_FUNCTION__); - g_free(unzip_data); - goto end; - } - - zip_data = zip_file + sizeof(struct _lfh) + local_file_header->filename_len + local_file_header->extra_field_len; - unzip_data = g_malloc(local_file_header->uncompressed_size); - gulong uncompressed_size = local_file_header->uncompressed_size; - - if (!(*unzip_size = uncompress_data(unzip_data, uncompressed_size, zip_data, local_file_header->compressed_size))) { - g_free(unzip_data); - unzip_data = NULL; - goto end; - } - -end: - return(unzip_data); -} - -static VikDEM *vik_dem_read_srtm_hgt(FILE *f, const gchar *basename, gboolean zip) +static VikDEM *vik_dem_read_srtm_hgt(const gchar *file_name, const gchar *basename, gboolean zip) { gint i, j; VikDEM *dem; - struct stat stat; off_t file_size; gint16 *dem_mem = NULL; - gint16 *dem_file = NULL; + gchar *dem_file = NULL; const gint num_rows_3sec = 1201; const gint num_rows_1sec = 3601; gint num_rows; - int fd = fileno(f); + GMappedFile *mf; gint arcsec; + GError *error = NULL; dem = g_malloc(sizeof(VikDEM)); @@ -316,19 +285,22 @@ static VikDEM *vik_dem_read_srtm_hgt(FILE *f, const gchar *basename, gboolean zi dem->columns = g_ptr_array_new(); dem->n_columns = 0; - if (fstat(fd, &stat) == -1) - g_error("%s(): fstat failed on %s\n", __PRETTY_FUNCTION__, basename); - if ((dem_file = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *) -1) - g_error("%s(): mmap failed on %s\n", __PRETTY_FUNCTION__, basename); - - file_size = stat.st_size; - dem_mem = dem_file; + if ((mf = g_mapped_file_new(file_name, FALSE, &error)) == NULL) { + g_critical(_("Couldn't map file %s: %s"), file_name, error->message); + g_error_free(error); + g_free(dem); + return NULL; + } + file_size = g_mapped_file_get_length(mf); + dem_file = g_mapped_file_get_contents(mf); + if (zip) { void *unzip_mem = NULL; gulong ucsize; - if ((unzip_mem = unzip_hgt_file((gchar *)dem_file, &ucsize)) == NULL) { - munmap(dem_file, file_size); + if ((unzip_mem = unzip_file(dem_file, &ucsize)) == NULL) { + g_mapped_file_unref(mf); + g_ptr_array_foreach ( dem->columns, (GFunc)g_free, NULL ); g_ptr_array_free(dem->columns, TRUE); g_free(dem); return NULL; @@ -337,15 +309,16 @@ static VikDEM *vik_dem_read_srtm_hgt(FILE *f, const gchar *basename, gboolean zi dem_mem = unzip_mem; file_size = ucsize; } + else + dem_mem = (gint16 *)dem_file; if (file_size == (num_rows_3sec * num_rows_3sec * sizeof(gint16))) arcsec = 3; else if (file_size == (num_rows_1sec * num_rows_1sec * sizeof(gint16))) arcsec = 1; else { - g_warning("%s(): file %s does not have right size\n", __PRETTY_FUNCTION__, basename); - munmap(dem_file, file_size); - g_ptr_array_free(dem->columns, TRUE); + g_warning("%s(): file %s does not have right size", __PRETTY_FUNCTION__, basename); + g_mapped_file_unref(mf); g_free(dem); return NULL; } @@ -373,7 +346,7 @@ static VikDEM *vik_dem_read_srtm_hgt(FILE *f, const gchar *basename, gboolean zi if (zip) g_free(dem_mem); - munmap(dem_file, stat.st_size); + g_mapped_file_unref(mf); return dem; } @@ -381,7 +354,7 @@ static VikDEM *vik_dem_read_srtm_hgt(FILE *f, const gchar *basename, gboolean zi VikDEM *vik_dem_new_from_file(const gchar *file) { - FILE *f; + FILE *f=NULL; VikDEM *rv; gchar buffer[DEM_BLOCK_SIZE+1]; @@ -390,17 +363,14 @@ VikDEM *vik_dem_new_from_file(const gchar *file) gint cur_row = -1; const gchar *basename = a_file_basename(file); - /* FILE IO */ - f = fopen(file, "r"); - if ( !f ) + if ( g_access ( file, R_OK ) != 0 ) return NULL; if ( (strlen(basename)==11 || ((strlen(basename) == 15) && (basename[11] == '.' && basename[12] == 'z' && basename[13] == 'i' && basename[14] == 'p'))) && basename[7]=='.' && basename[8]=='h' && basename[9]=='g' && basename[10]=='t' && (basename[0] == 'N' || basename[0] == 'S') && (basename[3] == 'E' || basename[3] =='W')) { gboolean is_zip_file = (strlen(basename) == 15); - rv = vik_dem_read_srtm_hgt(f, basename, is_zip_file); - fclose(f); + rv = vik_dem_read_srtm_hgt(file, basename, is_zip_file); return(rv); } @@ -408,9 +378,15 @@ VikDEM *vik_dem_new_from_file(const gchar *file) rv = g_malloc(sizeof(VikDEM)); /* Header */ + f = g_fopen(file, "r"); + if ( !f ) { + g_free ( rv ); + return NULL; + } buffer[fread(buffer, 1, DEM_BLOCK_SIZE, f)] = '\0'; if ( ! dem_parse_header ( buffer, rv ) ) { g_free ( rv ); + fclose(f); return NULL; } /* TODO: actually use header -- i.e. GET # OF COLUMNS EXPECTED */ @@ -439,6 +415,7 @@ VikDEM *vik_dem_new_from_file(const gchar *file) /* TODO - class C records (right now says 'Invalid' and dies) */ fclose(f); + f = NULL; /* 24k scale */ if ( rv->horiz_units == VIK_DEM_HORIZ_UTM_METERS && rv->n_columns >= 2 ) @@ -459,6 +436,7 @@ void vik_dem_free ( VikDEM *dem ) guint i; for ( i = 0; i < dem->n_columns; i++) g_free ( GET_COLUMN(dem, i)->points ); + g_ptr_array_foreach ( dem->columns, (GFunc)g_free, NULL ); g_ptr_array_free ( dem->columns, TRUE ); g_free ( dem ); } @@ -502,24 +480,23 @@ static gboolean dem_get_ref_points_elev_dist(VikDEM *dem, pos.lat = north/3600; /* order of the data: sw, nw, ne, se */ - cols[0] = (gint) floor((east - dem->min_east) / dem->east_scale); /* sw */ + /* sw */ + cols[0] = (gint) floor((east - dem->min_east) / dem->east_scale); rows[0] = (gint) floor((north - dem->min_north) / dem->north_scale); - //ll[0].lon = (east - fabs(fmod(east, dem->east_scale)))/3600; - //ll[0].lat = (north - fabs(fmod(north, dem->north_scale)))/3600; ll[0].lon = (dem->min_east + dem->east_scale*cols[0])/3600; ll[0].lat = (dem->min_north + dem->north_scale*rows[0])/3600; - - cols[1] = cols[0]; /*nw*/ + /* nw */ + cols[1] = cols[0]; rows[1] = rows[0] + 1; ll[1].lon = ll[0].lon; ll[1].lat = ll[0].lat + (gdouble)dem->north_scale/3600; - - cols[2] = cols[0] + 1; /*ne*/ + /* ne */ + cols[2] = cols[0] + 1; rows[2] = rows[0] + 1; ll[2].lon = ll[0].lon + (gdouble)dem->east_scale/3600; ll[2].lat = ll[0].lat + (gdouble)dem->north_scale/3600; - - cols[3] = cols[0] + 1; /*se*/ + /* se */ + cols[3] = cols[0] + 1; rows[3] = rows[0]; ll[3].lon = ll[0].lon + (gdouble)dem->east_scale/3600; ll[3].lat = ll[0].lat;