/************************************************************************\
* C64 printfox to portable pixmap converter 2-May-93                     *
* By Pasi 'Albert' Ojala (c) 1991-1998                                   *
*    albert@cs.tut.fi  albert@cc.tut.fi                                  *
*                                                                        *
* 22-Jan-95 TABsize=8, cleaning up                                       *
*                                                                        *
* PageFox format by Nicolas Welte 06-Jul-1998                            *
*    welte@chemie.uni-konstanz.de                                        *
*                                                                        *
* 21-Jul-98 Reformatting and cleaning up of the source code              *
*           Also, reduced memory consumption and added '-m' flag  -Pasi  *
*                                                                        *
\************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char UBYTE;

char *vers="\0$VER: foxtoppm 1.3 22-Jul-98\n";

#define TABLESIZE	65000

static UBYTE gfxmem[TABLESIZE];
static int width, height, mode;
static int flags = 0;

void Convert(char *name);

#define F_MULTI    (1<<0)
#define F_ERROR    (1<<7)


int main(int argc, char *argv[]) {
    int i, pointer = 0, repeats, c, size = 0;
    char *inFile = NULL, *outFile = NULL;
    FILE *inFp;

    for (i=1; i<argc; i++) {
	if (argv[i][0]=='-') {
	    for (c=1; argv[i][c]; c++) {
		switch (argv[i][c]) {
		case 'm':
		    flags |= F_MULTI;
		    break;
		default:
		    flags |= F_ERROR;
		}
	    }
	} else {
	    if (!inFile) {
		inFile = argv[i];
	    } else if (!outFile) {
		outFile = argv[i];
	    } else {
		flags |= F_ERROR;
	    }
	}
    }
    if ((flags & F_ERROR)) {
	fprintf(stderr, "\n%s", vers+7);
	fprintf(stderr, "Usage: %s [-m] [printfoxfile] [ppmfile]\n", argv[0]);
	fprintf(stderr, "       m - force multicolor mode\n");
	exit(10);
	return EXIT_FAILURE;
    }

    if (inFile) {
	inFp = fopen(inFile, "rb");
	if (!inFp) {
	    fprintf(stderr, "Could not open %s for reading\n", inFile);
	    return EXIT_FAILURE;
	}
    } else {
	inFp = stdin;
    }

    mode = fgetc(inFp);
    size++;
    if (mode == EOF) {
	fprintf(stderr,
		"Unexpected EOF while reading file type\n");
	if (inFp != stdin)
	    fclose(inFp);
	return EXIT_FAILURE;
    }

    switch (mode) {
    case 0x50:
	height = fgetc(inFp);
	width  = fgetc(inFp);
	size += 2;
	if (height == EOF || width == EOF) {
	    fprintf(stderr,
		    "Unexpected EOF while reading picture size\n");
	    if (inFp != stdin)
		fclose(inFp);
	    return EXIT_FAILURE;
	}
	c = 2 + height*4;       /* skip ID and outline info */
	size += 2 + height*4;
	while (c--) {
	    (void)fgetc(inFp);
	}
	fprintf(stderr, "PG (short RLE) %d(w) x %d(h)\n", width, height);
	break;
    case 0x47:
	width  = 80;
	height = 50;
	fprintf(stderr, "GB (long RLE) %d(w) x %d(h)\n", width, height);
	break;
    case 0x42:
	width  = 40;
	height = 25;
	fprintf(stderr, "BS %s(single screen) %d(w) x %d(h)\n",
		(flags & F_MULTI)?"multicolor ":"",
		width, height);
	break;
    case 0x01:
	width  = 40;
	height = 25;
	fprintf(stderr, "Uncompressed %s%d(w) x %d(h)\n",
		(flags & F_MULTI)?"multicolor ":"",
		width, height);
	break;
    default:
	fprintf(stderr, "ID not recognized (%d)\n", mode);
	if (inFp != stdin)
	    fclose(inFp);
	return EXIT_FAILURE;
    }
    if (mode==0x01) {
	/* Uncompressed */
	for (i=0; i<8000; i++) {
	    gfxmem[i] = (c = fgetc(inFp));
	    if (c == EOF) {
		fprintf(stderr,
			"Unexpected EOF while reading graphics data\n");
		break;
	    }
	}
	if (inFp != stdin)
	    fclose(inFp);
	Convert(outFile);
	return 0;
    }

    /* 0x50 PG(short RLE) 0x47 GB(long RLE), 0x42 small (printfox) */
    while (pointer < TABLESIZE) {
	c = fgetc(inFp);
	if (c == EOF)
	    break;
	size++;
	if (c == 0x9b) {
	    /* Repeat */
	    c = fgetc(inFp);
	    if (c == EOF)
		break;
	    size++;
	    repeats = c;
	    if (mode == 0x50) {
		if (repeats == 0)
		    repeats = 256;
	    } else {
		c = fgetc(inFp);
		if (c == EOF)
		    break;
		size++;
		repeats += c*256;
	    }
	    c = fgetc(inFp);
	    if (c == EOF)
		break;
	    size++;
	    while (repeats--) {
		if (pointer<0 || pointer>=TABLESIZE) {
		    fprintf(stderr,
			    "Pixel table overrun: %d\n",
			    pointer);
		    break;
		}
		gfxmem[pointer++] = c;
	    }
	} else {
	    gfxmem[pointer++] = c;
	}
    }
    c = fgetc(inFp);
    if (c != EOF) {
	fprintf(stderr, "Extra bytes in the input file\n");
    }
    if (inFp != stdin)
	fclose(inFp);
    fprintf(stderr, "%d bytes compressed, %d uncompressed\n",
	    size, pointer);
    Convert(outFile);
    return 0;
}


void Convert(char *name) {
    int x,y,pos,z;
    static const UBYTE bitmask[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
    static const UBYTE bitmask2[4] = {0xc0,0x30,0x0c,0x03};
    FILE *handle;
    UBYTE *buffer = malloc(3*width*8);

    if (!buffer) {
	fprintf(stderr, "Could not allocate %d bytes\n", 3*width*8);
	return;
    }

    fprintf(stderr,"Converting picture\n");
    if (name) {
	handle = fopen(name, "wb");
    } else {
	handle = stdout;
    }
    if (!handle) {
	fprintf(stderr, "Could not open %s for writing\n", name);
	free(buffer);
	return;
    }
    if ((flags & F_MULTI))
	fprintf(handle,"P6\n%d %d\n255\n", width*4, height*8);
    else
	fprintf(handle,"P6\n%d %d\n255\n", width*8, height*8);

    if ((flags & F_MULTI)) {
	for (y=0; y<height*8; y++) {
	    for (x=0; x<width*4; x++) {
		pos  = (y%8)+(x/4)*8+(y/8)*320;    /* grafix memory byte */

		z = (3-((gfxmem[pos] & bitmask2[x%4])>>((3-x%4)*2)))*255/3;

		buffer[3*x]   = z;
		buffer[3*x+1] = z;
		buffer[3*x+2] = z;
	    }
	    fwrite(buffer, width*4, 3, handle);
	}
    } else {
	for (y=0; y<height*8; y++) {
	    for (x=0; x<width*8; x++) {
		pos = (y%8)+(x/8)*8+(y/8)*width*8;    /* grafix memory byte */

		if ((gfxmem[pos] & bitmask[x%8])) {
		    buffer[3*x]   = 0;
		    buffer[3*x+1] = 0;
		    buffer[3*x+2] = 0;
		} else {
		    buffer[3*x]   = 255;
		    buffer[3*x+1] = 255;
		    buffer[3*x+2] = 255;
		}
	    }
	    fwrite(buffer, width*8, 3, handle);
	}
    }
    if (handle != stdout)
	fclose(handle);
    free(buffer);
}


