/* xbmtopbm.c - read an X bitmap file and produce a portable bitmap
**
** Copyright (C) 1988 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include <sys/types.h>
#include "pbm.h"

main( argc, argv )
int argc;
char *argv[];
    {
    FILE *ifd;
    register bit *bitrow, *bP;
    int rows, cols, row, col, charcount;
    char *data, mask;

    pm_progname = argv[0];

    if ( argc > 2 )
	pm_usage( "[bitmapfile]" );
    
    if ( argc == 2 )
	ifd = pm_openr( argv[1] );
    else
	ifd = stdin;

    ReadBitmapFile( ifd, &cols, &rows, &data );

    pm_close( ifd );

    pbm_writepbminit( stdout, cols, rows );
    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 );
	}

    exit( 0 );
    }


#ifdef	SYSV
#include <string.h>
#define rindex strrchr
#else	SYSV
#include <strings.h>
#endif	SYSV

#define MAX_LINE 200

ReadBitmapFile( stream, widthP, heightP, dataP )
FILE *stream;
int *widthP, *heightP;
char **dataP;
    {
    char line[MAX_LINE], name_and_type[MAX_LINE];
    char *ptr, *t;
    int bytes, bytes_per_line, value, version10p, raster_length, padding;

    *widthP = *heightP = -1;

    for ( ; ; )
	{
	if ( ! fgets( line, MAX_LINE, stream ) )
	    break;
	if ( strlen( line ) == MAX_LINE - 1 )
	    pm_error( "line too long", 0,0,0,0,0 );

	if (sscanf(line, "#define %s %d", name_and_type, &value) == 2)
	    {
	    if ( ! (t = rindex( name_and_type, '_' )) )
		t = name_and_type;
	    else
		t++;
	    if ( ! strcmp( "width", t ) )
		*widthP = value;
	    if ( ! strcmp( "height", t ) )
		*heightP = value;
	    continue;
	    }
	
	if ( sscanf( line, "static short %s = {", name_and_type ) == 1 )
	    {
	    version10p = 1;
	    break;
	    }
	else if ( sscanf( line, "static char %s = {", name_and_type ) == 1 )
	    {
	    version10p = 0;
	    break;
	    }
	else
	    continue;
	}
 
    if ( ! (t = rindex( name_and_type, '_' )) )
	t = name_and_type;
    else
	t++;
    
    if ( *widthP == -1 )
	pm_error( "invalid width", 0,0,0,0,0 );
    if ( *heightP == -1 )
	pm_error( "invalid height", 0,0,0,0,0 );

    padding = 0;
    if ( ((*widthP % 16) >= 1) && ((*widthP % 16) <= 8) && version10p )
	padding = 1;

    bytes_per_line = (*widthP+7)/8 + padding;
    
    raster_length =  bytes_per_line * *heightP;
    *dataP = (char *) malloc( raster_length );
    if ( *dataP == (char *) 0 )
	pm_error( "out of memory", 0,0,0,0,0 );

    if ( version10p )
	for ( bytes = 0, ptr = *dataP; bytes < raster_length; bytes += 2 )
	    {
	    if ( fscanf( stream, " 0x%x%*[,}]%*[ \n]", &value ) != 1 )
		pm_error( "error scanning bits item", 0,0,0,0,0 );
	    *(ptr++) = value & 0xff;
	    if ( (! padding) || ((bytes+2) % bytes_per_line) )
		*(ptr++) = value >> 8;
	    }
	else
	    for ( bytes = 0, ptr = *dataP; bytes < raster_length; bytes++ )
		{
		if ( fscanf( stream, " 0x%x%*[,}]%*[ \n]", &value ) != 1 )
		    pm_error( "error scanning bits item", 0,0,0,0,0 );
		*(ptr++) = value;
		}
    }
