about summary refs log tree commit diff
path: root/converter/pbm/xbmtopbm.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/pbm/xbmtopbm.c')
-rw-r--r--converter/pbm/xbmtopbm.c568
1 files changed, 352 insertions, 216 deletions
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c
index 7779a9b5..9505ba67 100644
--- a/converter/pbm/xbmtopbm.c
+++ b/converter/pbm/xbmtopbm.c
@@ -1,4 +1,4 @@
-/* xbmtopbm.c - read an X bitmap file and produce a portable bitmap
+/* xbmtopbm.c - read an X bitmap file and produce a PBM image
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
 **
@@ -10,246 +10,382 @@
 ** implied warranty.
 */
 
+
+#include <assert.h>
 #include <string.h>
 
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "nstring.h"
 #include "pbm.h"
+#include "bitreverse.h"
 
-#define TRUE 1
-#define FALSE 0
 
-static void ReadBitmapFile ARGS(( FILE* stream, int* widthP, int* heightP, char** dataP ));
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, row, col, charcount;
-    char* data;
-    char mask;
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-        pm_usage( "[bitmapfile]" );
-    
-    if ( argc == 2 )
-        ifp = pm_openr( argv[1] );
-    else
-        ifp = stdin;
-
-    ReadBitmapFile( ifp, &cols, &rows, &data );
-
-    pm_close( ifp );
-
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
-
-    for ( row = 0; row < rows; ++row )
-        {
-        charcount = 0;
-        mask = 1;
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-            {
-            if ( charcount >= 8 )
-                {
-                ++data;
-                charcount = 0;
-                mask = 1;
-                }
-            *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE;
-            ++charcount;
-            mask = mask << 1;
-            }
-        ++data;
-        pbm_writepbmrow( stdout, bitrow, cols, 0 );
-        }
+#define MAX_LINE 500
+
+static unsigned int hexTable[256];
+    /* Hexadecimal ASCII translation table.  Constant */
+
+static void
+initHexTable(void) {
+
+    unsigned int i;
+
+    for (i = 0; i < 256; ++i)
+        hexTable[i] = 256;
+
+    hexTable['0'] =  0;
+    hexTable['1'] =  1;
+    hexTable['2'] =  2;
+    hexTable['3'] =  3;
+    hexTable['4'] =  4;
+    hexTable['5'] =  5;
+    hexTable['6'] =  6;
+    hexTable['7'] =  7;
+    hexTable['8'] =  8;
+    hexTable['9'] =  9;
+    hexTable['A'] = 10;
+    hexTable['B'] = 11;
+    hexTable['C'] = 12;
+    hexTable['D'] = 13;
+    hexTable['E'] = 14;
+    hexTable['F'] = 15;
+    hexTable['a'] = 10;
+    hexTable['b'] = 11;
+    hexTable['c'] = 12;
+    hexTable['d'] = 13;
+    hexTable['e'] = 14;
+    hexTable['f'] = 15;
+}
 
-    pm_close( stdout );
-    exit( 0 );
-    }
 
-#define MAX_LINE 500
 
 static void
-ReadBitmapFile( stream, widthP, heightP, dataP )
-     FILE* stream;
-     int* widthP;
-     int* heightP;
-     char** dataP;
-{
-  char line[MAX_LINE], name_and_type[MAX_LINE];
-  char* ptr;
-  char* t;
-  int version10, raster_length, v;
-  register int bytes, bytes_per_line, padding;
-  register int c1, c2, value1, value2;
-  int hex_table[256];
-  int found_declaration;
-  /* In scanning through the bitmap file, we have found the first
-     line of the C declaration of the array (the "static char ..."
-     or whatever line)
-     */
-  int eof;
-  /* We've encountered end of file while searching file */
-
-  *widthP = *heightP = -1;
-
-  found_declaration = FALSE;    /* Haven't found it yet; haven't even looked*/
-  eof = FALSE;                  /* Haven't encountered end of file yet */
-
-  while (!found_declaration && !eof) {
-    if ( fgets( line, MAX_LINE, stream ) == NULL )
-      eof = TRUE;
-    else {
-      if ( strlen( line ) == MAX_LINE - 1 )
-        pm_error( "line too long" );
-
-      if ( sscanf( line, "#define %s %d", name_and_type, &v ) == 2 ) {
-        if ( ( t = strrchr( name_and_type, '_' ) ) == NULL )
-          t = name_and_type;
+parseWidthHeightLine(const char *   const line,
+                     bool *         const gotWidthP,
+                     unsigned int * const widthP,
+                     bool *         const gotHeightP,
+                     unsigned int * const heightP) {
+
+    int rc;
+    char nameAndType[MAX_LINE];
+    unsigned int value;
+
+    rc = sscanf(line, "#define %s %u", nameAndType, &value);
+    if (rc == 2) {
+        const char * underscorePos = strrchr(nameAndType, '_');
+        const char * type;
+        if (underscorePos)
+            type = underscorePos + 1;
         else
-          ++t;
-        if ( STREQ( "width", t ) )
-          *widthP = v;
-        else if ( STREQ( "height", t ) )
-          *heightP = v;
-        continue;
-      }
+            type = nameAndType;
+        if (streq(type, "width")) {
+            *gotWidthP = TRUE;
+            *widthP = value;
+        } else if (streq(type, "height")) {
+            *gotHeightP = TRUE;
+            *heightP = value;
+        }
+    }
+}
+
+
+
+static void
+parseDeclaration(const char * const line,
+                 bool *       const isDeclarationP,
+                 bool *       const version10P) {
+/*----------------------------------------------------------------------------
+   Parse the XBM file line 'line' as the first line of the data structure
+   declaration, i.e. the one that looks like this:
+
+      static unsigned char myImage = {
+
+   Return as *isDeclarationP whether the line actually is such a line,
+   and if so, return as nameAndType what the variable name ('myImage'
+   in the example) is and as *version10P whether it's of the type used
+   by X10 as opposed to X11.
+-----------------------------------------------------------------------------*/
+    char nameAndType[MAX_LINE];
+    int rc;
         
-      if ( sscanf( line, "static short %s = {", name_and_type ) == 1 ) {
-        version10 = TRUE;
-        found_declaration = TRUE;
-      }
-      else if ( sscanf( line, "static char %s = {", name_and_type ) == 1 ) {
-        version10 = FALSE;
-        found_declaration = TRUE;
-      }
-      else if (sscanf(line, 
-                      "static unsigned char %s = {", name_and_type ) == 1 ) {
-        version10 = FALSE;
-        found_declaration = TRUE;
-      }
+    rc = sscanf(line, "static short %s = {", nameAndType);
+    if (rc == 1) {
+        *version10P     = TRUE;
+        *isDeclarationP = TRUE;
+    } else {
+        int rc;
+        rc = sscanf(line, "static char %s = {", nameAndType);
+        if (rc == 1) {
+            *version10P     = FALSE;
+            *isDeclarationP = TRUE;
+        } else {
+            int rc;
+            rc = sscanf(line, "static unsigned char %s = {", nameAndType);
+            if (rc == 1) {
+                *version10P     = FALSE;
+                *isDeclarationP = TRUE;
+            } else
+                *isDeclarationP = FALSE;
+        }
     }
-  }
- 
-  if (!found_declaration) 
-    pm_error("Unable to find a line in the file containing the start "
-             "of C array declaration (\"static char\" or whatever)");
-
-  if ( *widthP == -1 )
-    pm_error( "invalid width" );
-  if ( *heightP == -1 )
-    pm_error( "invalid height" );
-
-  padding = 0;
-  if ( ((*widthP % 16) >= 1) && ((*widthP % 16) <= 8) && version10 )
-    padding = 1;
-
-  bytes_per_line = (*widthP+7)/8 + padding;
+}
+
+
+
+static void
+getXbmHeader(FILE *         const ifP,
+             unsigned int * const widthP,
+             unsigned int * const heightP,
+             bool *         const version10P) {
+
+    bool foundDeclaration;
+        /* In scanning through the bitmap file, we have found the first
+           line of the C declaration of the array (the "static char ..."
+           or whatever line)
+        */
+    bool gotWidth, gotHeight;
+        /* We found the line in the bitmap file that gives the width
+           or height, respectively, of the image (and have set
+           *widthP or *heightP to the value in it).
+        */
+
+    bool eof;
+        /* We've encountered end of file while searching file */
+
+    gotWidth = FALSE;
+    gotHeight = FALSE;
+    foundDeclaration = FALSE;    /* Haven't found it yet; haven't even looked*/
+    eof = FALSE;                 /* Haven't encountered end of file yet */
+
+    while (!foundDeclaration && !eof) {
+        char * rc;
+        char line[MAX_LINE];
+
+        rc = fgets(line, MAX_LINE, ifP);
+        if (rc == NULL)
+            eof = TRUE;
+        else {
+            if (strlen(line) == MAX_LINE - 1)
+                pm_error("A line in the input file is %u characters long.  "
+                         "%u is the maximum we can handle",
+                         strlen(line), MAX_LINE-1);
+
+            parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP);
+
+            parseDeclaration(line, &foundDeclaration, version10P);
+        }
+    }
+
+    if (!foundDeclaration) 
+        pm_error("Unable to find a line in the file containing the start "
+                 "of C array declaration (\"static char\" or whatever)");
+
+    if (!gotWidth)
+        pm_error("Unable to find the #define statement that gives the "
+                 "width of the image, before the data structure "
+                 "declaration.");
+    if (!gotHeight)
+        pm_error("Unable to find the #define statement that gives the "
+                 "height of the image, before the data structure "
+                 "declaration.");
+}
+
+
+
+static void
+getHexByte(FILE *         const ifP,
+           unsigned int * const valueP) {
+
+    int c1, c2;
+    unsigned int value;
+
+    c1 = getc(ifP);
+    c2 = getc(ifP);
+    if (c1 == EOF || c2 == EOF)
+        pm_error("EOF / read error");
+
+    assert(c1 >= 0); assert(c1 < 256);
+    assert(c2 >= 0); assert(c2 < 256);
     
-  raster_length =  bytes_per_line * *heightP;
-  *dataP = (char*) malloc( raster_length );
-  if ( *dataP == (char*) 0 )
-    pm_error( "out of memory" );
-
-  /* Initialize hex_table. */
-  for ( c1 = 0; c1 < 256; ++c1 )
-    hex_table[c1] = 256;
-  hex_table['0'] = 0;
-  hex_table['1'] = 1;
-  hex_table['2'] = 2;
-  hex_table['3'] = 3;
-  hex_table['4'] = 4;
-  hex_table['5'] = 5;
-  hex_table['6'] = 6;
-  hex_table['7'] = 7;
-  hex_table['8'] = 8;
-  hex_table['9'] = 9;
-  hex_table['A'] = 10;
-  hex_table['B'] = 11;
-  hex_table['C'] = 12;
-  hex_table['D'] = 13;
-  hex_table['E'] = 14;
-  hex_table['F'] = 15;
-  hex_table['a'] = 10;
-  hex_table['b'] = 11;
-  hex_table['c'] = 12;
-  hex_table['d'] = 13;
-  hex_table['e'] = 14;
-  hex_table['f'] = 15;
-
-  if ( version10 )
-    for ( bytes = 0, ptr = *dataP; bytes < raster_length; bytes += 2 ) {
-      while ( ( c1 = getc( stream ) ) != 'x' )
-        if ( c1 == EOF )
-          pm_error( "EOF / read error" );
-      c1 = getc( stream );
-      c2 = getc( stream );
-      if ( c1 == EOF || c2 == EOF )
-        pm_error( "EOF / read error" );
-      value1 = ( hex_table[c1] << 4 ) + hex_table[c2];
-      if ( value1 >= 256 )
-        pm_error( "syntax error" );
-      c1 = getc( stream );
-      c2 = getc( stream );
-      if ( c1 == EOF || c2 == EOF )
-        pm_error( "EOF / read error" );
-      value2 = ( hex_table[c1] << 4 ) + hex_table[c2];
-      if ( value2 >= 256 )
-        pm_error( "syntax error" );
-      *ptr++ = value2;
-      if ( ( ! padding ) || ( ( bytes + 2 ) % bytes_per_line ) )
-        *ptr++ = value1;
+    value = (hexTable[c1] << 4) + hexTable[c2];
+    if (value >= 256)
+        pm_error("Invalid XBM input.  What should be a two digit "
+                 "hexadecimal cipher is instead '%c%c'", c1, c2);
+
+    *valueP = value;
+}
+
+
+                     
+static void
+readX10Raster(FILE *          const ifP,
+              unsigned int    const rasterLength,
+              unsigned char * const data,
+              unsigned int    const bytesPerLine,
+              bool            const mustPad) {
+
+    unsigned int bytesDone;
+    unsigned char * p;
+
+    for (bytesDone = 0, p = &data[0];
+         bytesDone < rasterLength;
+         bytesDone += 2) {
+
+        unsigned int value1;
+        unsigned int value2;
+
+        while (getc(ifP) != 'x') {}  /* Read up through the 'x' in 0x1234 */
+
+        getHexByte(ifP, &value1);  /* Read first two hex digits */
+        getHexByte(ifP, &value2);  /* Read last two hex digits */
+
+        *p++ = value2;
+
+        if (!mustPad || ((bytesDone + 2) % bytesPerLine))
+            *p++ = value1;
     }
-  else
-    for ( bytes = 0, ptr = *dataP; bytes < raster_length; ++bytes ) {
-      /*
-       ** Skip until digit is found.
-       */
-      for ( ; ; )
-        {
-          c1 = getc( stream );
-          if ( c1 == EOF )
-            pm_error( "EOF / read error" );
-          value1 = hex_table[c1];
-          if ( value1 != 256 )
-            break;
-        }
-      /*
-       ** Loop on digits.
-       */
-      for ( ; ; ) {
-        c2 = getc( stream );
-        if ( c2 == EOF )
-          pm_error( "EOF / read error" );
-        value2 = hex_table[c2];
-        if ( value2 != 256 ) {
-          value1 = (value1 << 4) | value2;
-          if ( value1 >= 256 )
-            pm_error( "syntax error" );
+}
+
+
+
+static void
+readX11Raster(FILE * const ifP,
+              unsigned int const rasterLength,
+              unsigned char * data) {
+
+    unsigned int i;
+
+    for (i = 0; i < rasterLength; ++i) {
+        unsigned int value;
+        int c;
+
+        /* Read up through the 'x' in 0x12 */
+        while ((c = getc(ifP))) {
+            if (c == EOF)
+                pm_error("EOF where 0x expected");
+            else if (toupper(c) == 'X')
+                break;
         }
-        else if ( c2 == 'x' || c2 == 'X' )
-          if ( value1 == 0 )
-            continue;
-          else pm_error( "syntax error" );
-        else break;
-      }
-      *ptr++ = value1;
+
+        getHexByte(ifP, &value);  /* Read the two hex digits */
+
+        assert(value < 256);
+
+        data[i] = value;
     }
 }
 
 
-/*  CHANGE HISTORY:
 
-  99.09.08 bryanh    Recognize "static unsigned char" declaration.
+static void
+readBitmapFile(FILE *           const ifP,
+               unsigned int *   const widthP,
+               unsigned int *   const heightP,
+               unsigned char ** const dataP) {
+
+    bool version10;
+    unsigned int rasterLength;
+    unsigned int width, height;
+    unsigned char * data;
 
+    unsigned int bytesPerLine;
+    bool mustPad;
 
+    getXbmHeader(ifP, &width, &height, &version10);
 
+    *widthP = width;
+    *heightP = height;
 
+    mustPad = (width % 16 >= 1 && width % 16 <= 8 && version10);
+
+    bytesPerLine = (width + 7) / 8 + (mustPad ? 1 : 0);
+    
+    rasterLength = bytesPerLine * height;
+
+    MALLOCARRAY(data, rasterLength);
+    if (data == NULL)
+        pm_error("Unable to allocate memory for the %u-byte raster",
+                 rasterLength);
+
+    if (version10)
+        readX10Raster(ifP, rasterLength, data, bytesPerLine, mustPad);
+    else
+        readX11Raster(ifP, rasterLength, data);
+
+    *dataP = data;
+}
+
+
+
+int
+main(int    argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    bit * bitrow;
+    unsigned int rows, cols;
+    unsigned int row;
+    unsigned char * data;
+    const char * inputFileName;
+    unsigned char * p;
+        /* Cursor in raster data data[] */
+    
+    initHexTable();
+
+    pbm_init(&argc, argv);
+
+    if (argc-1 > 1)
+        pm_error("The only possible argument is the input file name.  "
+                 "You specified %u arguments", argc-1);
+    
+    if (argc-1 > 0)
+        inputFileName = argv[1];
+    else
+        inputFileName = "-";
+
+    ifP = pm_openr(inputFileName);
+
+    readBitmapFile(ifP, &cols, &rows, &data);
+
+    pm_close(ifP);
+
+    pbm_writepbminit(stdout, cols, rows, 0);
+    bitrow = pbm_allocrow_packed(cols);
+
+    p = &data[0];  /* Start at beginning of raster */
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int const bytesPerRow = pbm_packed_bytes(cols);
+        unsigned int i;
+        
+        for (i = 0; i < bytesPerRow; ++i)
+            bitrow[i] = bitreverse[*p++];
+            
+        if (cols % 8 > 0) {
+            bitrow[bytesPerRow-1] >>= 8 - cols % 8;
+            bitrow[bytesPerRow-1] <<= 8 - cols % 8;
+        }
+            
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+    }
+
+    pbm_freerow(bitrow);
+    free(data);
+    pm_close(stdout);
+
+    return 0;
+}
+
+/*  CHANGE HISTORY:
+
+  99.09.08 bryanh    Recognize "static unsigned char" declaration.
+
+  06.10 (afu)
+   Changed bitrow from plain to raw, write function from pbm_writepbmrow()
+   to pbm_writepbmrow_packed().
+   Retired bitwise transformation functions.
 
 */
+