about summary refs log tree commit diff
path: root/lib/libpbm2.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpbm2.c')
-rw-r--r--lib/libpbm2.c146
1 files changed, 124 insertions, 22 deletions
diff --git a/lib/libpbm2.c b/lib/libpbm2.c
index d04328ef..a8e4b0f6 100644
--- a/lib/libpbm2.c
+++ b/lib/libpbm2.c
@@ -10,9 +10,12 @@
 ** implied warranty.
 */
 
+#include <limits.h>
+
 #include "pbm.h"
 #include "libpbm.h"
 #include "fileio.h"
+#include "pam.h"
 
 static bit 
 getbit (FILE * const file) {
@@ -54,25 +57,65 @@ pbm_readpbminitrest( file, colsP, rowsP )
         pm_error("Number of columns in header is too large.");
     }
 
+
+
+static void
+validateComputableSize(unsigned int const cols,
+                       unsigned int const rows) {
+/*----------------------------------------------------------------------------
+   Validate that the dimensions of the image are such that it can be
+   processed in typical ways on this machine without worrying about
+   overflows.  Note that in C, arithmetic is always modulus
+   arithmetic, so if your values are too big, the result is not what
+   you expect.  That failed expectation can be disastrous if you use
+   it to allocate memory.
+
+   A common operation is adding 1 or 2 to the highest row or
+   column number in the image, so we make sure that's possible.
+-----------------------------------------------------------------------------*/
+    if (cols > INT_MAX - 2)
+        pm_error("image width (%u) too large to be processed", cols);
+    if (rows > INT_MAX - 2)
+        pm_error("image height (%u) too large to be processed", rows);
+}
+
+
+
 void
-pbm_readpbminit( file, colsP, rowsP, formatP )
-    FILE* file;
-    int* colsP;
-    int* rowsP;
-    int* formatP;
-    {
-    /* Check magic number. */
-    *formatP = pm_readmagicnumber( file );
-    switch ( PBM_FORMAT_TYPE(*formatP) )
-    {
-        case PBM_TYPE:
-    pbm_readpbminitrest( file, colsP, rowsP );
-    break;
+pbm_readpbminit(FILE * const ifP,
+                int *  const colsP,
+                int *  const rowsP,
+                int *  const formatP) {
+
+    *formatP = pm_readmagicnumber(ifP);
+
+    switch (PAM_FORMAT_TYPE(*formatP)) {
+    case PBM_TYPE:
+        pbm_readpbminitrest(ifP, colsP, rowsP);
+        break;
+
+    case PGM_TYPE:
+        pm_error("The input file is a PGM, not a PBM.  You may want to "
+                 "convert it to PBM with 'pamditherbw | pamtopnm' or "
+                 "'pamthreshold | pamtopnm'");
+
+    case PPM_TYPE:
+        pm_error("The input file is a PPM, not a PBM.  You may want to "
+                 "convert it to PBM with 'ppmtopgm', 'pamditherbw', and "
+                 "'pamtopnm'");
 
+    case PAM_TYPE:
+        pm_error("The input file is a PAM, not a PBM.  "
+                 "If it is a black and white image, you can convert it "
+                 "to PBM with 'pamtopnm'");
+        break;
     default:
-    pm_error( "bad magic number - not a pbm file" );
-    }
+        pm_error("bad magic number - not a Netpbm file");
     }
+    validateComputableSize(*colsP, *rowsP);
+}
+
+
 
 void
 pbm_readpbmrow( file, bitrow, cols, format )
@@ -114,8 +157,8 @@ pbm_readpbmrow( file, bitrow, cols, format )
 
 
 void
-pbm_readpbmrow_packed(FILE *          const file, 
-                      unsigned char * const packed_bits,
+pbm_readpbmrow_packed(FILE *          const fileP, 
+                      unsigned char * const packedBits,
                       int             const cols, 
                       int             const format) {
 
@@ -126,22 +169,22 @@ pbm_readpbmrow_packed(FILE *          const file,
 
         /* We first clear the return buffer, then set ones where needed */
         for (byteIndex = 0; byteIndex < pbm_packed_bytes(cols); ++byteIndex)
-            packed_bits[byteIndex] = 0x00;
+            packedBits[byteIndex] = 0x00;
 
         for (col = 0; col < cols; ++col) {
             unsigned char mask;
-            mask = getbit(file) << (7 - col % 8);
-            packed_bits[col / 8] |= mask;
+            mask = getbit(fileP) << (7 - col % 8);
+            packedBits[col / 8] |= mask;
         }
     }
     break;
 
     case RPBM_FORMAT: {
         int bytes_read;
-        bytes_read = fread(packed_bits, 1, pbm_packed_bytes(cols), file);
+        bytes_read = fread(packedBits, 1, pbm_packed_bytes(cols), fileP);
              
         if (bytes_read < pbm_packed_bytes(cols)) {
-            if (feof(file)) 
+            if (feof(fileP)) 
                 if (bytes_read == 0) 
                     pm_error("Attempt to read a raw PBM image row, but "
                              "no more rows left in file.");
@@ -160,6 +203,65 @@ pbm_readpbmrow_packed(FILE *          const file,
 
 
 
+void
+pbm_readpbmrow_bitoffset(FILE *          const ifP,
+                         unsigned char * const packedBits, 
+                         int             const cols,
+                         int             const format,
+                         unsigned int    const offset) {
+/*----------------------------------------------------------------------------
+   Read PBM packed bitrow from file 'ifP' (raster format given by
+   'cols' and 'format') and shift right 'offset' bits.
+
+   Read it into packedBits[], preserving surrounding image data.
+
+   Logic not tested for negative offsets.
+-----------------------------------------------------------------------------*/
+    unsigned int const rsh = offset % 8;
+    unsigned int const lsh = (8 - rsh) % 8;
+    unsigned char * const window = &packedBits[offset/8];
+        /* Area of packed row buffer into which we read the image data.
+           Aligned to nearest byte boundary to the left, so the first
+           few bits might contain original data, not output.
+        */
+    unsigned int const last = pbm_packed_bytes(cols+rsh) - 1;
+        /* Position within window of rightmost byte after shift */
+
+    /* The original leftmost and rightmost chars. */
+    unsigned char const origHead = window[0];
+    unsigned char const origEnd  = window[last];
+
+    pbm_readpbmrow_packed(ifP, window, cols, format);
+
+    if (rsh > 0) {
+        /* Target slot doesn't start on byte boundary; right-shift. */
+        unsigned char carryover;
+        unsigned int i;
+  
+        carryover = (origHead >> lsh) << lsh;
+
+        for (i = 0; i <= last; ++i) {
+            unsigned char const t = window[i] << lsh;
+            window[i] = carryover | window[i] >> rsh;
+            carryover = t;
+        }
+    }
+  
+    if ((cols + rsh) % 8 > 0) {
+        /* Adjust rightmost char */
+        unsigned int  const trs = (cols + rsh) % 8;
+        unsigned int  const tls = 8 - trs;
+        unsigned char const rightBits =
+            ((unsigned char)(origEnd << trs) >> trs);
+        unsigned char const leftBits =
+            ((unsigned char)(window[last] >> tls) << tls);
+
+        window[last] =  leftBits | rightBits;
+    }
+} 
+
+
+
 bit**
 pbm_readpbm( file, colsP, rowsP )
     FILE* file;