about summary refs log tree commit diff
path: root/lib/libpam.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpam.c')
-rw-r--r--lib/libpam.c145
1 files changed, 133 insertions, 12 deletions
diff --git a/lib/libpam.c b/lib/libpam.c
index d19534e2..9875331d 100644
--- a/lib/libpam.c
+++ b/lib/libpam.c
@@ -90,7 +90,12 @@ validateComputableSize(struct pam * const pamP) {
    the size of a tuple row, in bytes, can be represented by an 'int'.
 
    Another common operation is adding 1 or 2 to the highest row, column,
-   or plane number in the image, so we make sure that's possible.
+   or plane number in the image, so we make sure that's possible.  And in
+   bitmap images, rounding up to multiple of 8 is common, so we provide for
+   that too.
+
+   Note that it's still the programmer's responsibility to ensure that his
+   code, using values known to have been validated here, cannot overflow.
 -----------------------------------------------------------------------------*/
     if (pamP->width == 0)
         pm_error("Width is zero.  Image must be at least one pixel wide");
@@ -111,10 +116,10 @@ validateComputableSize(struct pam * const pamP) {
 
         if (depth > INT_MAX - 2)
             pm_error("image depth (%u) too large to be processed", depth);
-        if (pamP->width > INT_MAX - 2)
+        if (pamP->width > INT_MAX - 10)
             pm_error("image width (%u) too large to be processed",
                      pamP->width);
-        if (pamP->height > INT_MAX - 2)
+        if (pamP->height > INT_MAX - 10)
             pm_error("image height (%u) too large to be processed",
                      pamP->height);
     }
@@ -122,12 +127,22 @@ validateComputableSize(struct pam * const pamP) {
 
 
 
+static void
+validateComputableMaxval(const struct pam * const pamP) {
+/*----------------------------------------------------------------------------
+  This is similar to validateComputableSize, but for the maxval.
+-----------------------------------------------------------------------------*/
+    pgm_validateComputableMaxval(pamP->maxval);
+}
+
+
+
 tuple
 pnm_allocpamtuple(const struct pam * const pamP) {
 
     tuple retval;
 
-    retval = malloc(allocationDepth(pamP) * sizeof(retval[0]));
+    MALLOCARRAY(retval, allocationDepth(pamP));
 
     if (retval == NULL)
         pm_error("Out of memory allocating %u-plane tuple",
@@ -211,6 +226,24 @@ pnm_createBlackTuple(const struct pam * const pamP,
 
 
 
+void
+pnm_createWhiteTuple(const struct pam * const pamP,
+                     tuple *            const whiteTupleP) {
+/*----------------------------------------------------------------------------
+   Create a "white" tuple.  By that we mean a tuple all of whose elements are
+   the maxval.  If it's an RGB, grayscale, or b&w pixel, that means it's
+   white.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    *whiteTupleP = pnm_allocpamtuple(pamP);
+
+    for (i = 0; i < pamP->depth; ++i)
+        (*whiteTupleP)[i] = pamP->maxval;
+}
+
+
+
 static tuple *
 allocPamRow(const struct pam * const pamP) {
 /*----------------------------------------------------------------------------
@@ -289,7 +322,7 @@ pnm_allocrowimage(const struct pam * const pamP) {
 
     unsigned char * retval;
 
-    retval = malloc(size);
+    MALLOCARRAY(retval, size);
 
     if (retval == NULL)
         pm_error("Unable to allocate %u bytes for a row image buffer",
@@ -405,9 +438,9 @@ pnm_setpamrow(const struct pam * const pamP,
               tuple *            const tuplerow,
               sample             const value) {
 
-    int col;
+    unsigned int col;
     for (col = 0; col < pamP->width; ++col) {
-        int plane;
+        unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane)
             tuplerow[col][plane] = value;
     }
@@ -416,6 +449,22 @@ pnm_setpamrow(const struct pam * const pamP,
 
 
 
+static void
+setSeekableAndRasterPos(struct pam * const pamP) {
+
+    if (pamP->size >= PAM_STRUCT_SIZE(is_seekable))
+        pamP->is_seekable = pm_is_seekable(pamP->file);
+
+    if (pamP->size >= PAM_STRUCT_SIZE(raster_pos)) {
+        if (pamP->is_seekable)
+            pm_tell2(pamP->file, &pamP->raster_pos, sizeof(pamP->raster_pos));
+    }
+}
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
+
 #define MAX_LABEL_LENGTH 8
 #define MAX_VALUE_LENGTH 255
 
@@ -424,7 +473,7 @@ parseHeaderLine(const char * const buffer,
                 char *       const label,
                 char *       const value) {
 /*----------------------------------------------------------------------------
-   We truncate the labe to MAX_LABEL_LENGTH and the value to
+   We truncate the label to MAX_LABEL_LENGTH and the value to
    MAX_VALUE_LENGTH.  There must be at least that much space (plus space
    for a terminating NUL) at 'label' and 'value', respectively.
 -----------------------------------------------------------------------------*/
@@ -465,6 +514,7 @@ parseHeaderLine(const char * const buffer,
         value[valueCurs] = '\0';
     }
 }
+#pragma GCC diagnostic pop
 
 
 
@@ -699,7 +749,7 @@ readpaminitrest(struct pam * const pamP) {
     if (pamP->maxval == 0)
         pm_error("MAXVAL value is zero in PAM header");
     if (pamP->maxval > PAM_OVERALL_MAXVAL)
-        pm_error("MAXVAL value (%lu) in PAM header is greater than %u",
+        pm_error("MAXVAL value (%lu) in PAM header is greater than %lu",
                  pamP->maxval, PAM_OVERALL_MAXVAL);
 }
 
@@ -945,9 +995,13 @@ pnm_readpaminit(FILE *       const file,
     pamP->plainformat = FALSE;
         /* See below for complex explanation of why this is FALSE. */
 
+    setSeekableAndRasterPos(pamP);
+
     interpretTupleType(pamP);
 
     validateComputableSize(pamP);
+
+    validateComputableMaxval(pamP);
 }
 
 
@@ -1032,7 +1086,7 @@ pnm_writepaminit(struct pam * const pamP) {
 
     if (pamP->maxval > PAM_OVERALL_MAXVAL)
         pm_error("maxval (%lu) passed to pnm_writepaminit() "
-                 "is greater than %u", pamP->maxval, PAM_OVERALL_MAXVAL);
+                 "is greater than %lu", pamP->maxval, PAM_OVERALL_MAXVAL);
 
     if (pamP->len < PAM_STRUCT_SIZE(tuple_type)) {
         tupleType = "";
@@ -1053,10 +1107,10 @@ pnm_writepaminit(struct pam * const pamP) {
 
     interpretTupleType(pamP);
 
-    pamP->len = MIN(pamP->size, PAM_STRUCT_SIZE(opacity_plane));
-
     switch (PAM_FORMAT_TYPE(pamP->format)) {
     case PAM_TYPE:
+        validateComputableSize(pamP);
+        validateComputableMaxval(pamP);
         /* See explanation below of why we ignore 'pm_plain_output' here. */
         fprintf(pamP->file, "P7\n");
         writeComments(pamP);
@@ -1113,6 +1167,10 @@ pnm_writepaminit(struct pam * const pamP) {
         pm_error("Invalid format passed to pnm_writepaminit(): %d",
                  pamP->format);
     }
+
+    setSeekableAndRasterPos(pamP);
+
+    pamP->len = MIN(pamP->size, PAM_STRUCT_SIZE(raster_pos));
 }
 
 
@@ -1394,6 +1452,66 @@ pnm_backgroundtuple(struct pam *  const pamP,
 
 
 
+tuple
+pnm_backgroundtuplerow(const struct pam * const pamP,
+                       tuple            * const tuplerow) {
+/*-----------------------------------------------------------------------------
+  Guess a good background color for an image that contains row 'tuplerow'
+  (probably top or bottom edge), described by *pamP.
+
+  This function was copied from libpnm3.c's pnm_backgroundxelrow() and
+  modified to use tuples instead of xels.
+-----------------------------------------------------------------------------*/
+    tuple bgtuple;
+
+    bgtuple = pnm_allocpamtuple(pamP);
+
+    assert(pamP->width > 0);
+
+    if (pamP->width == 1)
+        pnm_assigntuple(pamP, bgtuple, tuplerow[0]);
+    else {
+        tuple const l = tuplerow[0];
+        tuple const r = tuplerow[pamP->width-1];
+
+        if (pnm_tupleequal(pamP, l, r)) {
+            /* Both corners are same color, so that's the background color,
+               without any extra computation.
+            */
+            pnm_assigntuple(pamP, bgtuple, l);
+        } else {
+            /* Corners are different */
+
+            if (pamP->depth == 1 && pamP->maxval == 1) {
+                /* It's black and white, with one corner black, the other
+                   white.  We consider whichever color is most prevalent in
+                   the row the background color.
+                */
+                unsigned int col;
+                unsigned int blackCt;
+
+                for (col = 0, blackCt = 0; col < pamP->width; ++col) {
+                    if (tuplerow[col] == 0)
+                        ++blackCt;
+                }
+                if (blackCt > pamP->width / 2)
+                    bgtuple[0] = 0;
+                else
+                    bgtuple[0] = pamP->maxval;
+            } else {
+                /* Use the cartesian mean of the two corner colors */
+                unsigned int plane;
+
+                for (plane = 0; plane < pamP->depth; ++plane)
+                    bgtuple[plane] = (l[plane] + r[plane])/2;
+            }
+        }
+    }
+    return bgtuple;
+}
+
+
+
 /*=============================================================================
    pm_system() Standard Input feeder and Standard Output accepter functions.
 =============================================================================*/
@@ -1433,3 +1551,6 @@ pm_accept_to_pamtuples(int    const pipeToSuckFd,
 
     pm_close(inpamP->file);
 }
+
+
+