about summary refs log tree commit diff
path: root/lib/libpamn.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpamn.c')
-rw-r--r--lib/libpamn.c285
1 files changed, 219 insertions, 66 deletions
diff --git a/lib/libpamn.c b/lib/libpamn.c
index c7610100..fe004e91 100644
--- a/lib/libpamn.c
+++ b/lib/libpamn.c
@@ -10,6 +10,7 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "pam.h"
 #include "fileio.h"
 #include "pm_gamma.h"
@@ -18,15 +19,19 @@
 
 
 
-tuplen *
-pnm_allocpamrown(const struct pam * const pamP) {
+static void
+allocpamrown(const struct pam * const pamP,
+             tuplen **          const tuplerownP,
+             const char **      const errorP) {
 /*----------------------------------------------------------------------------
    We assume that the dimensions of the image are such that arithmetic
    overflow will not occur in our calculations.  NOTE: pnm_readpaminit()
    ensures this assumption is valid.
 -----------------------------------------------------------------------------*/
-    const int bytes_per_tuple = pamP->depth * sizeof(samplen);
+    int const bytes_per_tuple = pamP->depth * sizeof(samplen);
+
     tuplen * tuplerown;
+    const char * error;
 
     /* The tuple row data structure starts with 'width' pointers to
        the tuples, immediately followed by the 'width' tuples
@@ -35,64 +40,106 @@ pnm_allocpamrown(const struct pam * const pamP) {
 
     tuplerown = malloc(pamP->width * (sizeof(tuplen *) + bytes_per_tuple));
     if (tuplerown == NULL)
-        pm_error("Out of memory allocating space for a tuple row of\n"
-                 "%d tuples by %d samples per tuple by %d bytes per sample.",
-                 pamP->width, pamP->depth, sizeof(samplen));
-
-    {
+        asprintfN(&error, "Out of memory allocating space for a tuple row of"
+                  "%u tuples by %u samples per tuple by %u bytes per sample.",
+                  pamP->width, pamP->depth, sizeof(samplen));
+    else {
         /* Now we initialize the pointers to the individual tuples to make this
            a regulation C two dimensional array.
         */
         
-        char *p;
-        int i;
+        unsigned char * p;
+        unsigned int i;
         
-        p = (char*) (tuplerown + pamP->width);  /* location of Tuple 0 */
-        for (i = 0; i < pamP->width; i++) {
+        p = (unsigned char*) (tuplerown + pamP->width);
+            /* location of Tuple 0 */
+        for (i = 0; i < pamP->width; ++i) {
             tuplerown[i] = (tuplen) p;
             p += bytes_per_tuple;
         }
+        *errorP = NULL;
+        *tuplerownP = tuplerown;
     }
-    return(tuplerown);
 }
 
 
 
-void 
-pnm_readpamrown(const struct pam * const pamP, 
-                tuplen *           const tuplenrow) {
+tuplen *
+pnm_allocpamrown(const struct pam * const pamP) {
+/*----------------------------------------------------------------------------
+   We assume that the dimensions of the image are such that arithmetic
+   overflow will not occur in our calculations.  NOTE: pnm_readpaminit()
+   ensures this assumption is valid.
+-----------------------------------------------------------------------------*/
+    const char * error;
+    tuplen * tuplerown;
 
-    /* For speed, we don't check any of the inputs for consistency 
-       here (unless it's necessary to avoid crashing).  Any consistency
-       checking should have been done by a prior call to 
-       pnm_writepaminit().
-    */
-    assert(pamP->maxval != 0);
+    allocpamrown(pamP, &tuplerown, &error);
 
-    /* Need a special case for raw PBM because it has multiple tuples (8)
-       packed into one byte.
-    */
-    if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) {
-        int col;
-        bit *bitrow;
-        if (pamP->depth != 1)
-            pm_error("Invalid pam structure passed to pnm_readpamrow().  "
-                     "It says PBM format, but 'depth' member is not 1.");
-        bitrow = pbm_allocrow(pamP->width);
-        pbm_readpbmrow(pamP->file, bitrow, pamP->width, pamP->format);
-        for (col = 0; col < pamP->width; col++)
-            tuplenrow[col][0] = 
-                bitrow[col] == PBM_BLACK ? 0.0 : 1.0;
+    if (error) {
+        pm_errormsg("pnm_allocpamrown() failed.  %s", error);
+        strfree(error);
+        pm_longjmp();
+    }
+
+    return tuplerown;
+}
+
+
+
+static void
+readpbmrow(const struct pam * const pamP, 
+           tuplen *           const tuplenrow) {
+
+    bit * bitrow;
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
+
+    bitrow = pbm_allocrow(pamP->width);
+    
+    if (setjmp(jmpbuf) != 0) {
         pbm_freerow(bitrow);
+        pm_setjmpbuf(origJmpbufP);
+        pm_longjmp();
+    } else {
+        unsigned int col;
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
+
+        pbm_readpbmrow(pamP->file, bitrow, pamP->width, pamP->format);
+
+        for (col = 0; col < pamP->width; ++col)
+            tuplenrow[col][0] = bitrow[col] == PBM_BLACK ? 0.0 : 1.0;
+
+        pm_setjmpbuf(origJmpbufP);
+    }
+    pbm_freerow(bitrow);
+}
+
+
+
+static void
+readpamrow(const struct pam * const pamP, 
+           tuplen *           const tuplenrow) {
+
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
+    tuple * tuplerow;
+    
+    tuplerow = pnm_allocpamrow(pamP);
+    
+    if (setjmp(jmpbuf) != 0) {
+        pnm_freepamrow(tuplerow);
+        pm_setjmpbuf(origJmpbufP);
+        pm_longjmp();
     } else {
         float const scaler = 1.0 / pamP->maxval;
             /* Note: multiplication is faster than division, so we divide
                once here so we can multiply many times later.
             */
-        int col;
-        tuple * tuplerow;
 
-        tuplerow = pnm_allocpamrow(pamP);
+        unsigned int col;
+
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
 
         pnm_readpamrow(pamP, tuplerow);
         for (col = 0; col < pamP->width; ++col) {
@@ -100,15 +147,16 @@ pnm_readpamrown(const struct pam * const pamP,
             for (plane = 0; plane < pamP->depth; ++plane)
                 tuplenrow[col][plane] = tuplerow[col][plane] * scaler;
         }
-        pnm_freepamrow(tuplerow);
+        pm_setjmpbuf(origJmpbufP);
     }
+    pnm_freepamrow(tuplerow);
 }
 
 
 
 void 
-pnm_writepamrown(const struct pam * const pamP, 
-                 const tuplen *     const tuplenrow) {
+pnm_readpamrown(const struct pam * const pamP, 
+                tuplen *           const tuplenrow) {
 
     /* For speed, we don't check any of the inputs for consistency 
        here (unless it's necessary to avoid crashing).  Any consistency
@@ -121,20 +169,66 @@ pnm_writepamrown(const struct pam * const pamP,
        packed into one byte.
     */
     if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) {
-        int col;
-        bit *bitrow;
-        bitrow = pbm_allocrow(pamP->width);
-        for (col = 0; col < pamP->width; col++)
-            bitrow[col] = 
-                tuplenrow[col][0] < 0.5 ? PBM_BLACK : PBM_WHITE;
+        if (pamP->depth != 1)
+            pm_error("Invalid pam structure passed to pnm_readpamrow().  "
+                     "It says PBM format, but 'depth' member is not 1.");
+
+        readpbmrow(pamP, tuplenrow);
+    } else
+        readpamrow(pamP, tuplenrow);
+}
+
+
+
+static void
+writepbmrow(const struct pam * const pamP, 
+            const tuplen *     const tuplenrow) {
+
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
+    bit * bitrow;
+
+    bitrow = pbm_allocrow(pamP->width);
+
+    if (setjmp(jmpbuf) != 0) {
+        pbm_freerow(bitrow);
+        pm_setjmpbuf(origJmpbufP);
+        pm_longjmp();
+    } else {
+        unsigned int col;
+
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
+
+        for (col = 0; col < pamP->width; ++col)
+            bitrow[col] = tuplenrow[col][0] < 0.5 ? PBM_BLACK : PBM_WHITE;
         pbm_writepbmrow(pamP->file, bitrow, pamP->width, 
                         pamP->format == PBM_FORMAT);
-        pbm_freerow(bitrow);
+
+        pm_setjmpbuf(origJmpbufP);
+    }
+    pbm_freerow(bitrow);
+} 
+
+
+
+static void
+writepamrow(const struct pam * const pamP, 
+            const tuplen *     const tuplenrow) {
+
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
+    tuple * tuplerow;
+    
+    tuplerow = pnm_allocpamrow(pamP);
+    
+    if (setjmp(jmpbuf) != 0) {
+        pnm_freepamrow(tuplerow);
+        pm_setjmpbuf(origJmpbufP);
+        pm_longjmp();
     } else {
-        tuple * tuplerow;
-        int col;
+        unsigned int col;
 
-        tuplerow = pnm_allocpamrow(pamP);
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
 
         for (col = 0; col < pamP->width; ++col) {
             unsigned int plane;
@@ -143,8 +237,32 @@ pnm_writepamrown(const struct pam * const pamP,
                     (tuplenrow[col][plane] * pamP->maxval + 0.5);
         }    
         pnm_writepamrow(pamP, tuplerow);
-        pnm_freepamrow(tuplerow);
+
+        pm_setjmpbuf(origJmpbufP);
     }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+void 
+pnm_writepamrown(const struct pam * const pamP, 
+                 const tuplen *     const tuplenrow) {
+
+    /* For speed, we don't check any of the inputs for consistency 
+       here (unless it's necessary to avoid crashing).  Any consistency
+       checking should have been done by a prior call to 
+       pnm_writepaminit().
+    */
+    assert(pamP->maxval != 0);
+
+    /* Need a special case for raw PBM because it has multiple tuples (8)
+       packed into one byte.
+    */
+    if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE)
+        writepbmrow(pamP, tuplenrow);
+    else
+        writepamrow(pamP, tuplenrow);
 }
 
 
@@ -152,8 +270,8 @@ pnm_writepamrown(const struct pam * const pamP,
 tuplen **
 pnm_allocpamarrayn(const struct pam * const pamP) {
     
-    tuplen **tuplenarray;
-    int row;
+    tuplen ** tuplenarray;
+    const char * error;
 
     /* If the speed of this is ever an issue, it might be sped up a little
        by allocating one large chunk.
@@ -161,12 +279,33 @@ pnm_allocpamarrayn(const struct pam * const pamP) {
     
     MALLOCARRAY(tuplenarray, pamP->height);
     if (tuplenarray == NULL) 
-        pm_error("Out of memory allocating the row pointer section of "
-                 "a %u row array", pamP->height);
-
-    for (row = 0; row < pamP->height; row++) {
-        tuplenarray[row] = pnm_allocpamrown(pamP);
+        asprintfN(&error,
+                  "Out of memory allocating the row pointer section of "
+                  "a %u row array", pamP->height);
+    else {
+        unsigned int rowsDone;
+
+        rowsDone = 0;
+        error = NULL;
+
+        while (rowsDone < pamP->height && !error) {
+            allocpamrown(pamP, &tuplenarray[rowsDone], &error);
+            if (!error)
+                ++rowsDone;
+        }
+        if (error) {
+            unsigned int row;
+            for (row = 0; row < rowsDone; ++row)
+                pnm_freepamrown(tuplenarray[rowsDone]);
+            free(tuplenarray);
+        }
+    }
+    if (error) {
+        pm_errormsg("pnm_allocpamarrayn() failed.  %s", error);
+        strfree(error);
+        pm_longjmp();
     }
+
     return(tuplenarray);
 }
 
@@ -191,16 +330,28 @@ pnm_readpamn(FILE *       const file,
              int          const size) {
 
     tuplen **tuplenarray;
-    int row;
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
 
     pnm_readpaminit(file, pamP, size);
     
     tuplenarray = pnm_allocpamarrayn(pamP);
     
-    for (row = 0; row < pamP->height; row++) 
-        pnm_readpamrown(pamP, tuplenarray[row]);
+    if (setjmp(jmpbuf) != 0) {
+        pnm_freepamarrayn(tuplenarray, pamP);
+        pm_setjmpbuf(origJmpbufP);
+        pm_longjmp();
+    } else {
+        unsigned int row;
 
-    return(tuplenarray);
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
+
+        for (row = 0; row < pamP->height; ++row) 
+            pnm_readpamrown(pamP, tuplenarray[row]);
+
+        pm_setjmpbuf(origJmpbufP);
+    }
+    return tuplenarray;
 }
 
 
@@ -209,11 +360,11 @@ void
 pnm_writepamn(struct pam * const pamP, 
               tuplen **    const tuplenarray) {
 
-    int row;
+    unsigned int row;
 
     pnm_writepaminit(pamP);
     
-    for (row = 0; row < pamP->height; row++) 
+    for (row = 0; row < pamP->height; ++row) 
         pnm_writepamrown(pamP, tuplenarray[row]);
 }
 
@@ -473,6 +624,8 @@ createUngammaMapOffset(const struct pam * const pamP,
    can be used in a reverse lookup to convert normalized ungamma'ed
    samplen values to integer sample values.  The 0.5 effectively does
    the rounding.
+
+   This never throws an error.  Return value NULL means failed.
 -----------------------------------------------------------------------------*/
     pnm_transformMap * retval;
     pnm_transformMap ungammaTransformMap;