head	1.2;
access;
symbols
	OCT93:1.2;
locks;
comment	@ * @;


1.2
date	93.06.11.16.33.37;	author Rhialto;	state Exp;
branches;
next	1.1;

1.1
date	93.06.11.14.53.53;	author Rhialto;	state Exp;
branches;
next	;


desc
@Convert IFF ILBM to g3 files
@


1.2
log
@First real RCS checkin
@
text
@/*
 * iff2fax.c
 *
 * Copyright (C) 1993 by Olaf 'Rhialto' Seibert. All rights reserved.
 *
 * $Id$
 * $Log$
 */

#include <stdlib.h>

#include "iffp/iff.h"
#include "iffp/ilbm.h"
#include "iffp/packer.h"
#include "faxfile.h"

void	       *IFFParseBase;
struct ParseInfo ParseInfo;
int		verbose;
int		bodyskip;
int		xoffset = 50;
int		yoffset = 50;
int		invert;

long props[] = { ID_ILBM, ID_BMHD, TAG_DONE };
long stops[] = { ID_ILBM, ID_BODY, TAG_DONE };

/* Assumes malloc()ed pointer */
void
memor(unsigned char *d, unsigned char *s, int size)
{
    if (((long) d & 0x01) == 0) {
	while (size >= 4) {
	    *(long *)d |= *(long *)s;
	    s += 4;
	    d += 4;
	    size -= 4;
	}
    }
    while (size > 0) {
	*d++ |= *s++;
	size--;
    }
}

void
meminvert(unsigned char *d, int size)
{
    if (((long) d & 0x01) == 0) {
	while (size >= 4) {
	    *(long *)d ^= 0xFFFFFFFF;
	    d += 4;
	    size -= 4;
	}
    }
    while (size > 0) {
	*d++ ^= 0xFF;
	size--;
    }
}

long
dobody(struct ParseInfo *pi, void *faxp)
{
    BitMapHeader   *bmhd;
    unsigned char  *plane1data,
		   *plane2data;
    int 	    planedatasize;
    int 	    bodydatabytes;
    unsigned char  *bodydata,
		   *bodydata2;
    int 	    bodydatasize;
    int 	    bytexoffset;
    int 	    line;
    int 	    bodywidth;
    int 	    plane;
    int 	    maskplane = -1;
    struct ContextNode *cn;
    long	    error;

    if (bodyskip) {
	bodyskip--;
	if (verbose)
	    printf("Skipping BODY.\n");
	return 0;
    }

    cn = CurrentChunk(pi->iff);
    bmhd = (BitMapHeader *)findpropdata(pi->iff, ID_ILBM, ID_BMHD);
    if (bmhd == NULL)
	return IFFERR_MANGLED;

    error = 0;
    /* Adjust for funny page sizes */
    if (bmhd->pageWidth < bmhd->w)
	bmhd->pageWidth = bmhd->w;
    bmhd->pageWidth += bmhd->x + xoffset;
    if (bmhd->pageWidth < LINE_BITS)
	bmhd->pageWidth = LINE_BITS;
    if (bmhd->pageHeight < bmhd->h)
	bmhd->pageHeight = bmhd->h;
    bmhd->pageHeight += bmhd->y + yoffset;
    bodywidth = RowBytes(bmhd->w);
    bytexoffset = (bmhd->x + xoffset + 7) / 8;

    if (bmhd->masking != mskNone) {
	maskplane = bmhd->nPlanes++;
    }

    if (verbose) {
	printf("X: %d Y: %d W: %d H: %d Planes: %d\n",
		bmhd->x, bmhd->y,
		bmhd->w, bmhd->h,
		bmhd->nPlanes);
    }

    planedatasize = RowBytes(bmhd->pageWidth);
    bodydatasize = 2048;    /* Arbitrary buffer size */

    plane1data = malloc(planedatasize + 4);
    plane2data = malloc(planedatasize + 4);
    bodydata = malloc(bodydatasize + 4);
    bodydatabytes = 0;
    if (plane1data == NULL || plane2data == NULL || bodydata == NULL) {
	error = IFFERR_NOMEM;
	goto fail;
    }

    faxout_begin_page(faxp, 1);

    memset(bodydata, 0, bodydatasize);          /* not needed */

    if (yoffset) {
	int		i;

	memset(plane1data, 0, planedatasize);
	for (i = 0; i < yoffset; i++)
	    tofax(faxp, plane1data, bmhd->pageWidth);
    }

    for (line = 0; line < bmhd->h; line++) {
	memset(plane1data, 0, planedatasize);   /* not needed */
	memset(plane2data, 0, planedatasize);

	for (plane = 0; plane < bmhd->nPlanes; plane++) {
	    /* Is the buffer half empty, and more data available? */
	    if (bodydatabytes <= (bodydatasize >> 1) &&
		ChunkMoreBytes(cn)) {
		/* Move remaining data to start of buffer */
		memcpy(bodydata, bodydata2, bodydatabytes);
		bodydata2 = bodydata;
		error = ReadChunkBytes(pi->iff,
				    bodydata + bodydatabytes,	    /* buf */
				    bodydatasize - bodydatabytes);  /* size */
		if (error <= 0) {
		    fprintf(stderr, "Read: error %d\n", error);
		    faxout_end_page(faxp);
		    goto fail;
		}
		bodydatabytes += error;
	    }
	    if (bodydatabytes <= 0) {
		error = IFFERR_MANGLED;
		fprintf(stderr, "Out of data??\n");
		faxout_end_page(faxp);
		goto fail;
	    }
	    /* Uncompress to plane2data */
	    if (bmhd->compression == cmpNone) {
		memcpy(plane2data, bodydata2 + bytexoffset, bodywidth);
		bodydata2 += bodywidth;
		bodydatabytes -= bodywidth;
	    } else {
		unsigned char  *s, *d;

		s = bodydata2;
		d = plane2data + bytexoffset;
		UnPackRow(&bodydata2, &d,    bodydatabytes, bodywidth);
			/* source      dest  source size    dest size */
		bodydatabytes -= (bodydata2 - s);
	    }
	    /* OR this plane (plane2) with previous planes (plane1) */
	    if (plane == 0) {
		memcpy(plane1data, plane2data, planedatasize);
	    } else if (plane != maskplane) {
		memor(plane1data, plane2data, planedatasize);
	    }
	} /* plane */
	if (invert)
	    meminvert(plane1data + bytexoffset, bodywidth);

	tofax(faxp, plane1data, bmhd->pageWidth);
    }
    faxout_end_page(faxp);

fail:
    if (plane1data)
	free(plane1data);
    if (plane2data)
	free(plane2data);
    if (bodydata)
	free(bodydata);

    return error;
}

long
dofile(char *iffname, struct faxout *faxp)
{
    long	    error;

    ParseInfo.iff = AllocIFF();
    error = openifile(&ParseInfo, iffname, IFFF_READ);
    if (error)
	goto fail1;

    error = parseifile(&ParseInfo, ID_FORM, ID_ILBM, props, NULL, stops);
    while (1) {
	switch (error) {
	case 0:     /* stop chunk (BODY). */
	    error = dobody(&ParseInfo, faxp);
	    break;
	case IFFERR_EOC:
	    if (verbose) printf("End Of Context.\n");
	    break;
	case IFFERR_EOF:
	    if (verbose) printf("EOF.\n");
	    goto eof;
	default:
	    fprintf(stderr, "Iffparse error %d\n", error);
	    goto eof;
	}
	error = getcontext(ParseInfo.iff);
    }
eof:
    closeifile(&ParseInfo);
fail1:
    FreeIFF(ParseInfo.iff);
    ParseInfo.iff = NULL;

    return error;
}

/*
 * Clean up system stuff in case of exit
 */
void
cleanup(void)
{
    if (IFFParseBase) {
	if (ParseInfo.iff) {
	    closeifile(&ParseInfo);
	    FreeIFF(ParseInfo.iff);
	}
	CloseLibrary(IFFParseBase);
    }
}

int
main(int argc, char **argv)
{
    char	   *outfile = "ilbm.g3";
    struct faxout  *faxp;
    int 	    rawfax = 1;
    int 	    append = 0;
    extern char    *optarg;
    extern int	    optind;
    extern int	    getopt(int, char **, char *);
    int 	    errflg = 0;
    int 	    c;

    while ((c = getopt(argc, argv, "aio:rs:vx:y:")) != -1) {
	switch (c) {
	case 'a':
	    append = TRUE;
	    break;
	case 'i':
	    invert = TRUE;
	    break;
	case 'o':
	    outfile = optarg;
	    break;
	case 'r':
	    rawfax++;
	    break;
	case 's':
	    bodyskip = atoi(optarg);
	    break;
	case 'v':
	    verbose = TRUE;
	    break;
	case 'x':
	    xoffset = atoi(optarg);
	    break;
	case 'y':
	    yoffset = atoi(optarg);
	    break;
	case '?':
	    errflg++;
	    break;
	}
    }

    if (errflg || optind >= argc) {
	printf(
"Usage: iff2fax [-o fax-file (ilbm.g3)] [-r raw faxfile] [-a (append)]\n"
"               [-sN skip N BODYs]\n"
"               [-x/y x/y-offset (50)] [-v] [-i (invert)] iff-files\n");
	exit(EXIT_FAILURE);
    }

    atexit(cleanup);

    IFFParseBase = OpenLibrary("iffparse.library", 0);
    if (IFFParseBase == NULL) {
	printf("Needs iffparse.\n");
	exit(10);
    }

    faxp = faxout_open_fp(fopen(outfile, append? "ab": "wb"), rawfax);
    if (faxp == NULL) {
	fprintf(stderr, "can't open output file %s.\n", outfile);
	goto fail;
    }

    while (optind < argc) {
	dofile(argv[optind], faxp);
	optind++;
    }

    faxout_close(faxp);
fail:
    /*CloseLibrary(IFFParseBase);*/
    /* atexit function cleans up here */
}
@


1.1
log
@Initial revision
@
text
@d5 3
@
