[GRASS-SVN] r71448 - grass/trunk/lib/raster

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Aug 31 06:57:11 PDT 2017


Author: mmetz
Date: 2017-08-31 06:57:11 -0700 (Thu, 31 Aug 2017)
New Revision: 71448

Modified:
   grass/trunk/lib/raster/open.c
   grass/trunk/lib/raster/range.c
Log:
rasterlib: fix segfault if NULLS are compressed, but not data

Modified: grass/trunk/lib/raster/open.c
===================================================================
--- grass/trunk/lib/raster/open.c	2017-08-31 07:56:16 UTC (rev 71447)
+++ grass/trunk/lib/raster/open.c	2017-08-31 13:57:11 UTC (rev 71448)
@@ -711,7 +711,7 @@
     fcb->null_row_ptr = NULL;
     if (R__.compress_nulls) {
 	fcb->null_row_ptr = G_calloc(fcb->cellhd.rows + 1, sizeof(off_t));
-	G_zero(fcb->row_ptr, (fcb->cellhd.rows + 1) * sizeof(off_t));
+	G_zero(fcb->null_row_ptr, (fcb->cellhd.rows + 1) * sizeof(off_t));
 	Rast__write_null_row_ptrs(fd, fcb->null_fd);
     }
 

Modified: grass/trunk/lib/raster/range.c
===================================================================
--- grass/trunk/lib/raster/range.c	2017-08-31 07:56:16 UTC (rev 71447)
+++ grass/trunk/lib/raster/range.c	2017-08-31 13:57:11 UTC (rev 71448)
@@ -22,6 +22,8 @@
 #define DEFAULT_CELL_MIN 1
 #define DEFAULT_CELL_MAX 255
 
+static void init_rstats(struct R_stats *);
+
 /*!
    \brief Remove floating-point range
 
@@ -241,6 +243,103 @@
 }
 
 /*!
+ * \brief Read raster stats
+ *
+ * Read the stats file <i>stats</i>. This file is
+ * written in binary using XDR format.
+ *
+ * An empty stats file indicates that all cells are NULL. This
+ * is a valid case, and the result should be an initialized rstats
+ * struct with no defined stats.  If the stats file is missing
+ * this function will create a default stats with count = 0.
+ *
+ * \param name map name
+ * \param mapset mapset name
+ * \param rstats pointer to R_stats structure which holds raster stats
+ *
+ * \return 1 on success
+ * \return 2 stats is empty
+ * \return -1 on error or stats file does not exist
+ */
+int Rast_read_rstats(const char *name, const char *mapset,
+		       struct R_stats *rstats)
+{
+    int fd;
+    char xdr_buf[2][XDR_DOUBLE_NBYTES];
+    DCELL dcell1, dcell2;
+    unsigned char cc[8];
+    char nbytes;
+    int i;
+    off_t count;
+
+    Rast_init();
+    init_rstats(rstats);
+
+    fd = -1;
+
+    if (!G_find_file2_misc("cell_misc", "stats", name, mapset)) {
+	G_debug(1, "Stats file does not exist");
+	return -1;
+    }
+
+    fd = G_open_old_misc("cell_misc", "stats", name, mapset);
+    if (fd < 0) {
+	G_warning(_("Unable to read stats file for <%s>"),
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+
+    if (read(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
+	/* if the stats file exists, but empty file, meaning Nulls */
+	close(fd);
+	G_debug(1, "Empty stats file meaning Nulls for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return 2;
+    }
+
+    G_xdr_get_double(&dcell1, xdr_buf[0]);
+    G_xdr_get_double(&dcell2, xdr_buf[1]);
+
+    rstats->sum = dcell1;
+    rstats->sumsq = dcell2;
+
+    /* count; see cell_values_int() in get_row.c */
+    nbytes = 1;
+    if (read(fd, &nbytes, 1) != 1) {
+	/* if the stats file exists, but empty file, meaning Nulls */
+	close(fd);
+	G_debug(1, "Unable to read byte count in stats file for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+
+    if (nbytes < 1 || nbytes > sizeof(off_t)) {
+	close(fd);
+	G_debug(1, "Invalid byte count in stats file for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+    if (read(fd, cc, nbytes) != nbytes) {
+	/* incorrect number of bytes for count */
+	close(fd);
+	G_debug(1, "Unable to read count in stats file for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+
+    count = 0;
+    for (i = nbytes - 1; i >= 0; i--) {
+	count = (count << 8);
+	count = count + cc[i];
+    }
+    rstats->count = count;
+
+    close(fd);
+
+    return 1;
+}
+
+/*!
  * \brief Write raster range file
  *
  * This routine writes the range information for the raster map
@@ -259,6 +358,8 @@
 {
     FILE *fp;
 
+    Rast_write_rstats(name, &(range->rstats));
+
     if (Rast_map_type(name, G_mapset()) != CELL_TYPE) {
 	G_remove_misc("cell_misc", "range", name);	/* remove the old file with this name */
 	G_fatal_error(_("Unable to write range file for <%s>"), name);
@@ -294,6 +395,8 @@
 
     Rast_init();
 
+    Rast_write_rstats(name, &(range->rstats));
+
     fd = G_open_new_misc("cell_misc", "f_range", name);
     if (fd < 0) {
 	G_remove_misc("cell_misc", "f_range", name);
@@ -318,6 +421,72 @@
 }
 
 /*!
+ * \brief Write raster stats file
+ *
+ * Write the stats file <tt>stats</tt>. This file is
+ * written in binary using XDR format. If the count is < 1
+ * in <em>rstats</em>, an empty <tt>stats</tt> file is created.
+ *
+ * \param name map name
+ * \param rstats pointer to R_stats which holds stats info
+ */
+void Rast_write_rstats(const char *name, const struct R_stats *rstats)
+{
+    int fd;
+    char xdr_buf[2][XDR_DOUBLE_NBYTES];
+    unsigned char cc[8];
+    char nbytes;
+    int i;
+    off_t count;
+
+    Rast_init();
+
+    fd = G_open_new_misc("cell_misc", "stats", name);
+    if (fd < 0) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    /* if count is zero, write empty file meaning Nulls */
+    if (rstats->count < 1) {
+	close(fd);
+	return;
+    }
+
+    G_xdr_put_double(xdr_buf[0], &rstats->sum);
+    G_xdr_put_double(xdr_buf[1], &rstats->sumsq);
+
+    if (write(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    /* count; see convert_int() in put_row.c */
+    count = rstats->count;
+    nbytes = 0;
+    for (i = 0; i < sizeof(off_t); i++) {
+	cc[i] = count & 0xff;
+	count >>= 8;
+	if (cc[i])
+	    nbytes = i;
+    }
+    nbytes++;
+
+    /* number of bytes needed for count */
+    if (write(fd, &nbytes, 1) != 1) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    if (write(fd, cc, nbytes) != nbytes) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    close(fd);
+}
+
+/*!
  * \brief Update range structure (CELL)
  *
  * Compares the <i>cat</i> value with the minimum and maximum values
@@ -412,12 +581,21 @@
 	    range->first_time = 0;
 	    range->min = cat;
 	    range->max = cat;
+
+	    range->rstats.sum = cat;
+	    range->rstats.sumsq = (DCELL) cat * cat;
+	    range->rstats.count = 1;
+
 	    continue;
 	}
 	if (cat < range->min)
 	    range->min = cat;
 	if (cat > range->max)
 	    range->max = cat;
+
+	range->rstats.sum += cat;
+	range->rstats.sumsq += (DCELL) cat * cat;
+	range->rstats.count += 1;
     }
 }
 
@@ -461,12 +639,20 @@
 	    range->first_time = 0;
 	    range->min = val;
 	    range->max = val;
+
+	    range->rstats.sum = val;
+	    range->rstats.sumsq = val * val;
+	    range->rstats.count = 1;
 	}
 	else {
 	    if (val < range->min)
 		range->min = val;
 	    if (val > range->max)
 		range->max = val;
+
+	    range->rstats.sum += val;
+	    range->rstats.sumsq += val * val;
+	    range->rstats.count += 1;
 	}
 
 	rast = G_incr_void_ptr(rast, size);
@@ -489,6 +675,9 @@
 {
     Rast_set_c_null_value(&(range->min), 1);
     Rast_set_c_null_value(&(range->max), 1);
+
+    init_rstats(&range->rstats);
+
     range->first_time = 1;
 }
 
@@ -538,6 +727,9 @@
 {
     Rast_set_d_null_value(&(range->min), 1);
     Rast_set_d_null_value(&(range->max), 1);
+
+    init_rstats(&range->rstats);
+
     range->first_time = 1;
 }
 
@@ -572,3 +764,10 @@
 	    *max = range->max;
     }
 }
+
+static void init_rstats(struct R_stats *rstats)
+{
+    Rast_set_d_null_value(&(rstats->sum), 1);
+    Rast_set_d_null_value(&(rstats->sumsq), 1);
+    rstats->count = 0;
+}



More information about the grass-commit mailing list