Blame converter/pbm/xbmtopbm.c

Packit 78deda
/* xbmtopbm.c - read an X bitmap file and produce a PBM image
Packit 78deda
**
Packit 78deda
** Copyright (C) 1988 by Jef Poskanzer.
Packit 78deda
**
Packit 78deda
** Permission to use, copy, modify, and distribute this software and its
Packit 78deda
** documentation for any purpose and without fee is hereby granted, provided
Packit 78deda
** that the above copyright notice appear in all copies and that both that
Packit 78deda
** copyright notice and this permission notice appear in supporting
Packit 78deda
** documentation.  This software is provided "as is" without express or
Packit 78deda
** implied warranty.
Packit 78deda
*/
Packit 78deda
Packit 78deda
Packit 78deda
#include <assert.h>
Packit 78deda
#include <string.h>
Packit 78deda
Packit 78deda
#include "pm_c_util.h"
Packit 78deda
#include "mallocvar.h"
Packit 78deda
#include "nstring.h"
Packit 78deda
#include "pbm.h"
Packit 78deda
#include "bitreverse.h"
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
#define MAX_LINE 500
Packit 78deda
Packit 78deda
static unsigned int hexTable[256];
Packit 78deda
    /* Hexadecimal ASCII translation table.  Constant */
Packit 78deda
Packit 78deda
static void
Packit 78deda
initHexTable(void) {
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
Packit 78deda
    for (i = 0; i < 256; ++i)
Packit 78deda
        hexTable[i] = 256;
Packit 78deda
Packit 78deda
    hexTable['0'] =  0;
Packit 78deda
    hexTable['1'] =  1;
Packit 78deda
    hexTable['2'] =  2;
Packit 78deda
    hexTable['3'] =  3;
Packit 78deda
    hexTable['4'] =  4;
Packit 78deda
    hexTable['5'] =  5;
Packit 78deda
    hexTable['6'] =  6;
Packit 78deda
    hexTable['7'] =  7;
Packit 78deda
    hexTable['8'] =  8;
Packit 78deda
    hexTable['9'] =  9;
Packit 78deda
    hexTable['A'] = 10;
Packit 78deda
    hexTable['B'] = 11;
Packit 78deda
    hexTable['C'] = 12;
Packit 78deda
    hexTable['D'] = 13;
Packit 78deda
    hexTable['E'] = 14;
Packit 78deda
    hexTable['F'] = 15;
Packit 78deda
    hexTable['a'] = 10;
Packit 78deda
    hexTable['b'] = 11;
Packit 78deda
    hexTable['c'] = 12;
Packit 78deda
    hexTable['d'] = 13;
Packit 78deda
    hexTable['e'] = 14;
Packit 78deda
    hexTable['f'] = 15;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
parseWidthHeightLine(const char *   const line,
Packit 78deda
                     bool *         const gotWidthP,
Packit 78deda
                     unsigned int * const widthP,
Packit 78deda
                     bool *         const gotHeightP,
Packit 78deda
                     unsigned int * const heightP) {
Packit 78deda
Packit 78deda
    int rc;
Packit 78deda
    char nameAndType[MAX_LINE];
Packit 78deda
    unsigned int value;
Packit 78deda
Packit 78deda
    rc = sscanf(line, "#define %s %u", nameAndType, &value);
Packit 78deda
    if (rc == 2) {
Packit 78deda
        const char * underscorePos = strrchr(nameAndType, '_');
Packit 78deda
        const char * type;
Packit 78deda
        if (underscorePos)
Packit 78deda
            type = underscorePos + 1;
Packit 78deda
        else
Packit 78deda
            type = nameAndType;
Packit 78deda
        if (streq(type, "width")) {
Packit 78deda
            *gotWidthP = TRUE;
Packit 78deda
            *widthP = value;
Packit 78deda
        } else if (streq(type, "height")) {
Packit 78deda
            *gotHeightP = TRUE;
Packit 78deda
            *heightP = value;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
parseDeclaration(const char * const line,
Packit 78deda
                 bool *       const isDeclarationP,
Packit 78deda
                 bool *       const version10P) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Parse the XBM file line 'line' as the first line of the data structure
Packit 78deda
   declaration, i.e. the one that looks like this:
Packit 78deda
Packit 78deda
      static unsigned char myImage = {
Packit 78deda
Packit 78deda
   Return as *isDeclarationP whether the line actually is such a line,
Packit 78deda
   and if so, return as nameAndType what the variable name ('myImage'
Packit 78deda
   in the example) is and as *version10P whether it's of the type used
Packit 78deda
   by X10 as opposed to X11.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    char nameAndType[MAX_LINE];
Packit 78deda
    int rc;
Packit 78deda
        
Packit 78deda
    rc = sscanf(line, "static short %s = {", nameAndType);
Packit 78deda
    if (rc == 1) {
Packit 78deda
        *version10P     = TRUE;
Packit 78deda
        *isDeclarationP = TRUE;
Packit 78deda
    } else {
Packit 78deda
        int rc;
Packit 78deda
        rc = sscanf(line, "static char %s = {", nameAndType);
Packit 78deda
        if (rc == 1) {
Packit 78deda
            *version10P     = FALSE;
Packit 78deda
            *isDeclarationP = TRUE;
Packit 78deda
        } else {
Packit 78deda
            int rc;
Packit 78deda
            rc = sscanf(line, "static unsigned char %s = {", nameAndType);
Packit 78deda
            if (rc == 1) {
Packit 78deda
                *version10P     = FALSE;
Packit 78deda
                *isDeclarationP = TRUE;
Packit 78deda
            } else
Packit 78deda
                *isDeclarationP = FALSE;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
getXbmHeader(FILE *         const ifP,
Packit 78deda
             unsigned int * const widthP,
Packit 78deda
             unsigned int * const heightP,
Packit 78deda
             bool *         const version10P) {
Packit 78deda
Packit 78deda
    bool foundDeclaration;
Packit 78deda
        /* In scanning through the bitmap file, we have found the first
Packit 78deda
           line of the C declaration of the array (the "static char ..."
Packit 78deda
           or whatever line)
Packit 78deda
        */
Packit 78deda
    bool gotWidth, gotHeight;
Packit 78deda
        /* We found the line in the bitmap file that gives the width
Packit 78deda
           or height, respectively, of the image (and have set
Packit 78deda
           *widthP or *heightP to the value in it).
Packit 78deda
        */
Packit 78deda
Packit 78deda
    bool eof;
Packit 78deda
        /* We've encountered end of file while searching file */
Packit 78deda
Packit 78deda
    gotWidth = FALSE;
Packit 78deda
    gotHeight = FALSE;
Packit 78deda
    foundDeclaration = FALSE;    /* Haven't found it yet; haven't even looked*/
Packit 78deda
    eof = FALSE;                 /* Haven't encountered end of file yet */
Packit 78deda
Packit 78deda
    while (!foundDeclaration && !eof) {
Packit 78deda
        char * rc;
Packit 78deda
        char line[MAX_LINE];
Packit 78deda
Packit 78deda
        rc = fgets(line, MAX_LINE, ifP);
Packit 78deda
        if (rc == NULL)
Packit 78deda
            eof = TRUE;
Packit 78deda
        else {
Packit 78deda
            if (strlen(line) == MAX_LINE - 1)
Packit 78deda
                pm_error("A line in the input file is %u characters long.  "
Packit 78deda
                         "%u is the maximum we can handle",
Packit 78deda
                         (unsigned)strlen(line), MAX_LINE-1);
Packit 78deda
Packit 78deda
            parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP);
Packit 78deda
Packit 78deda
            parseDeclaration(line, &foundDeclaration, version10P);
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if (!foundDeclaration) 
Packit 78deda
        pm_error("Unable to find a line in the file containing the start "
Packit 78deda
                 "of C array declaration (\"static char\" or whatever)");
Packit 78deda
Packit 78deda
    if (!gotWidth)
Packit 78deda
        pm_error("Unable to find the #define statement that gives the "
Packit 78deda
                 "width of the image, before the data structure "
Packit 78deda
                 "declaration.");
Packit 78deda
    if (!gotHeight)
Packit 78deda
        pm_error("Unable to find the #define statement that gives the "
Packit 78deda
                 "height of the image, before the data structure "
Packit 78deda
                 "declaration.");
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
getHexByte(FILE *         const ifP,
Packit 78deda
           unsigned int * const valueP) {
Packit 78deda
Packit 78deda
    int c1, c2;
Packit 78deda
    unsigned int value;
Packit 78deda
Packit 78deda
    c1 = getc(ifP);
Packit 78deda
    c2 = getc(ifP);
Packit 78deda
    if (c1 == EOF || c2 == EOF)
Packit 78deda
        pm_error("EOF / read error");
Packit 78deda
Packit 78deda
    assert(c1 >= 0); assert(c1 < 256);
Packit 78deda
    assert(c2 >= 0); assert(c2 < 256);
Packit 78deda
    
Packit 78deda
    value = (hexTable[c1] << 4) + hexTable[c2];
Packit 78deda
    if (value >= 256)
Packit 78deda
        pm_error("Invalid XBM input.  What should be a two digit "
Packit 78deda
                 "hexadecimal cipher is instead '%c%c'", c1, c2);
Packit 78deda
Packit 78deda
    *valueP = value;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
                     
Packit 78deda
static void
Packit 78deda
readX10Raster(FILE *          const ifP,
Packit 78deda
              unsigned int    const rasterLength,
Packit 78deda
              unsigned char * const data,
Packit 78deda
              unsigned int    const bytesPerLine,
Packit 78deda
              bool            const mustPad) {
Packit 78deda
Packit 78deda
    unsigned int bytesDone;
Packit 78deda
    unsigned char * p;
Packit 78deda
Packit 78deda
    for (bytesDone = 0, p = &data[0];
Packit 78deda
         bytesDone < rasterLength;
Packit 78deda
         bytesDone += 2) {
Packit 78deda
Packit 78deda
        unsigned int value1;
Packit 78deda
        unsigned int value2;
Packit 78deda
Packit 78deda
        while (getc(ifP) != 'x') {}  /* Read up through the 'x' in 0x1234 */
Packit 78deda
Packit 78deda
        getHexByte(ifP, &value1);  /* Read first two hex digits */
Packit 78deda
        getHexByte(ifP, &value2);  /* Read last two hex digits */
Packit 78deda
Packit 78deda
        *p++ = value2;
Packit 78deda
Packit 78deda
        if (!mustPad || ((bytesDone + 2) % bytesPerLine))
Packit 78deda
            *p++ = value1;
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
readX11Raster(FILE * const ifP,
Packit 78deda
              unsigned int const rasterLength,
Packit 78deda
              unsigned char * data) {
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
Packit 78deda
    for (i = 0; i < rasterLength; ++i) {
Packit 78deda
        unsigned int value;
Packit 78deda
        int c;
Packit 78deda
Packit 78deda
        /* Read up through the 'x' in 0x12 */
Packit 78deda
        while ((c = getc(ifP))) {
Packit 78deda
            if (c == EOF)
Packit 78deda
                pm_error("EOF where 0x expected");
Packit 78deda
            else if (toupper(c) == 'X')
Packit 78deda
                break;
Packit 78deda
        }
Packit 78deda
Packit 78deda
        getHexByte(ifP, &value);  /* Read the two hex digits */
Packit 78deda
Packit 78deda
        assert(value < 256);
Packit 78deda
Packit 78deda
        data[i] = value;
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
readBitmapFile(FILE *           const ifP,
Packit 78deda
               unsigned int *   const widthP,
Packit 78deda
               unsigned int *   const heightP,
Packit 78deda
               unsigned char ** const dataP) {
Packit 78deda
Packit 78deda
    bool version10;
Packit 78deda
    unsigned int rasterLength;
Packit 78deda
    unsigned int width, height;
Packit 78deda
    unsigned char * data;
Packit 78deda
Packit 78deda
    unsigned int bytesPerLine;
Packit 78deda
    bool mustPad;
Packit 78deda
Packit 78deda
    getXbmHeader(ifP, &width, &height, &version10);
Packit 78deda
Packit 78deda
    *widthP = width;
Packit 78deda
    *heightP = height;
Packit 78deda
Packit 78deda
    mustPad = (width % 16 >= 1 && width % 16 <= 8 && version10);
Packit 78deda
Packit 78deda
    bytesPerLine = (width + 7) / 8 + (mustPad ? 1 : 0);
Packit 78deda
    
Packit 78deda
    rasterLength = bytesPerLine * height;
Packit 78deda
Packit 78deda
    MALLOCARRAY(data, rasterLength);
Packit 78deda
    if (data == NULL)
Packit 78deda
        pm_error("Unable to allocate memory for the %u-byte raster",
Packit 78deda
                 rasterLength);
Packit 78deda
Packit 78deda
    if (version10)
Packit 78deda
        readX10Raster(ifP, rasterLength, data, bytesPerLine, mustPad);
Packit 78deda
    else
Packit 78deda
        readX11Raster(ifP, rasterLength, data);
Packit 78deda
Packit 78deda
    *dataP = data;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
int
Packit 78deda
main(int    argc,
Packit 78deda
     char * argv[]) {
Packit 78deda
Packit 78deda
    FILE * ifP;
Packit 78deda
    bit * bitrow;
Packit 78deda
    unsigned int rows, cols;
Packit 78deda
    unsigned int row;
Packit 78deda
    unsigned char * data;
Packit 78deda
    const char * inputFileName;
Packit 78deda
    unsigned char * p;
Packit 78deda
        /* Cursor in raster data data[] */
Packit 78deda
    
Packit 78deda
    initHexTable();
Packit 78deda
Packit 78deda
    pbm_init(&argc, argv);
Packit 78deda
Packit 78deda
    if (argc-1 > 1)
Packit 78deda
        pm_error("The only possible argument is the input file name.  "
Packit 78deda
                 "You specified %u arguments", argc-1);
Packit 78deda
    
Packit 78deda
    if (argc-1 > 0)
Packit 78deda
        inputFileName = argv[1];
Packit 78deda
    else
Packit 78deda
        inputFileName = "-";
Packit 78deda
Packit 78deda
    ifP = pm_openr(inputFileName);
Packit 78deda
Packit 78deda
    readBitmapFile(ifP, &cols, &rows, &data);
Packit 78deda
Packit 78deda
    pm_close(ifP);
Packit 78deda
Packit 78deda
    pbm_writepbminit(stdout, cols, rows, 0);
Packit 78deda
    bitrow = pbm_allocrow_packed(cols);
Packit 78deda
Packit 78deda
    p = &data[0];  /* Start at beginning of raster */
Packit 78deda
Packit 78deda
    for (row = 0; row < rows; ++row) {
Packit 78deda
        unsigned int const bytesPerRow = pbm_packed_bytes(cols);
Packit 78deda
        unsigned int i;
Packit 78deda
        
Packit 78deda
        for (i = 0; i < bytesPerRow; ++i)
Packit 78deda
            bitrow[i] = bitreverse[*p++];
Packit 78deda
Packit 78deda
        pbm_cleanrowend_packed(bitrow, cols);
Packit 78deda
        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    pbm_freerow(bitrow);
Packit 78deda
    free(data);
Packit 78deda
    pm_close(stdout);
Packit 78deda
Packit 78deda
    return 0;
Packit 78deda
}
Packit 78deda
Packit 78deda
/*  CHANGE HISTORY:
Packit 78deda
Packit 78deda
  99.09.08 bryanh    Recognize "static unsigned char" declaration.
Packit 78deda
Packit 78deda
  06.10 (afu)
Packit 78deda
   Changed bitrow from plain to raw, write function from pbm_writepbmrow()
Packit 78deda
   to pbm_writepbmrow_packed().
Packit 78deda
   Retired bitwise transformation functions.
Packit 78deda
Packit 78deda
*/
Packit 78deda