Dec 072017
 
C source to read a mac file.
File CREADMAC.ZIP from The Programmer’s Corner in
Category C Source Code
C source to read a mac file.
File Name File Size Zip Size Zip Type
READMAC.TXT 16000 5784 deflated

Download File CREADMAC.ZIP Here

Contents of the READMAC.TXT file





/*
***************************************************************
* READMAC.C - routines to read in and decode MacPaint and RLE files
*
* (c) Copyright 1987 by:
*
* Computerwise Consulting Services
* P.O. Box 813
* McLean, VA 22101
* (703) 280-2809
*
* All rights reserved.
*
* Permission is granted for personal use of this program, with the
* exception that the following potential users ARE EXPLICITLY DENIED
* PERMISSION TO RECEIVE, USE, OR TRANSFER THIS PROGRAM IN SOURCE OR
* OBJECT OR EXECUTABLE OR ANY OTHER FORM:
*
* 1) Lotus Development Corporation, and any employee thereof
* or consultant thereto;
*
* 2) ADAPSO, and any firm which is a member thereof, or any
* employee of such a firm.
*
* These two organizations have - in the opinion of CCS - acted as
* "software pirates" by continually and intentionally violating
* U.S. Copyright law, specifically by first "copy-protecting" software
* disks and then zealously prosecuting innocent users who exercised
* their rights under the law to make copies of their own property.
*
* Further, permission is granted to transfer this program only if
* it is transferred absolutely unmodified in any form.
*
***************************************************************
*/


/*
* Read MACPAINT file "fname" into mem_array.
*
* Returns -1 if error, else zero.
*/

readmac(fname)
BYTE *fname;/* Filename to open */
{
BYTE *eof;/* Pointer to physical EOF */
BYTE *p;
int handle, num_read;

#if DEBUG
long start;/* Time at start of decode */
#endif

handle = open(fname, O_RDONLY | O_BINARY);

if (handle == -1)
{
return(-1);/* Can't open file */
}

if ( isatty(handle) )
{
close(handle);
return(-1);/* Don't get smart! */
}

/*
* Read in all data
*/

num_read = read(handle, scratch, sizeof(scratch));
close(handle);

if ( num_read == -1 )
{
return(-1);/* Bad read */
}

eof = scratch;/* Set physical EOF */
eof += (unsigned) num_read;

/*
* Find start of actual data (skipping MacBinary and/or MacPaint headers)
*/

p = adjust(scratch);

/*
* If this is an RLE file, now's the time to find that out and
* decode it as such.
*/

if ( isrle(p, eof) )
{

if ( auto_invert )/* Are we inverting things? */
{
invert_rle( (rle_pic + 5) % 6 );/* Yes, invert this RLE image */
}

/*
* If this has filled our screen with the 6th RLE image, then
* flush it to the screen or the printer.
*/

if ( rle_pic >= 6 )
{
flush();
rle_pic = 0;
}

return(0);/* No errors, it's been decoded */
}

/*
* This is not an RLE image. However, we may have buffered up some
* RLE files prior to this non-RLE file which have yet to be
* displayed or printed. We had better display/print them now, 'cause
* we're about to overwrite the image with our new MacPaint file!
*/

if ( rle_pic )/* Got any RLE images? */
{
flush();/* Yes, display or print them */
rle_pic = 0;/* We ain't got them no more! */
}

/*
* Now decode it as a MacPaint file into mem_image
*/

#if DEBUG
start = ticker();/* Remember time at start of decoding */
#endif

get_mem_image(p, eof);/* Decode picture */

#if DEBUG
elapsed[next_elapsed++] =/* Calc duration of decode */
ticker() - start;
#endif


/*
* And automatically display or print it
*/

if ( auto_invert )/* Are we inverting things? */
{
invert();/* Yes, invert this image */
}

flush();
return(0);
}


/*
* Given a pointer p to the start of the in-memory image of a MACPAINT
* file, return a pointer to the first actual data byte.
*
* Some MACPAINT files include the MacBinary header up front. Others don't.
* All should have at least the MacPaint header. It all depends on
* the person that did the uploading.
*
* It is this routine's job to deduce the presence of any prologue,
* and return a pointer that skips over it. It must also set data_type
* to either ENCODED or RAW, per the file's format.
*/

BYTE *adjust(p)
BYTE *p;
{

data_type = ENCODED;/* Assume ENCODED, cause most files are */

/*
* Check for 32-bit MacPaint or FullPaint version as first thing in file
* (i.e. - no MacBinary header).
*
* NOTE: Some files that we have seen have a dummy 512-byte header
* of zeroes. All that we can figure is that somebody got ahold
* of a bunch of raw data, and needed to prepend some kind
* of header so that it would be readable as a MACPAINT file.
* This dummy 512-byte header of zeroes serves as the brush/pattern
* header. Although this following test doesn't specifically
* check for 512 bytes of zeroes at the front, such a zero
* header WILL be caught by this test, and will cause us to
* skip the first 512 bytes of the file. So all comes out right
* after all...
*/

if ( (p[0] == 0) && (p[1] == 0) && (p[2] == 0) && (p[3] < 5) )
{
return(p + 512);/* File starts with MacPaint header info */
}

/*
* Check for MacBinary header at front of file
*/

switch ( ismacbin(p) )
{
case 0:/* Not a MacBinary header, so assume all data */
return(p);

case 1:/* Screen Image (like StartupScreen) */
data_type = RAW;
return(p + 128);

case 2:/* Normal file with MacBinary and MacPaint headers */
return( p + 640 );
}
}



/*
* Examine potential MacBinary header at p, and return code describing it:
*
*0 = not a MacBinary header
*1 = file is Screen Image (RAW)
*2 = file is standard MacPaint file (ENCODED)
*/

ismacbin(p)
register struct _macbinary_header *p;
{
int i;
unsigned u;

u = p->name_size;

if (
(u > 63) ||/* If bad name size... */
(u == 0) ||
(p->zero != 0) ||/* ...or zero bytes aren't zero... */
(p->finder_info.zero != 0) ||
(p->version > 1)/* ...or odd version */
)
{
return(0);/* Not a MacBinary header */
}

/*
* Verify that the filename is all legal ASCII characters
*/

for ( i = 0; i < u; i++ )
{
if ( (p->filename[i] < ' ') || (p->filename[i] > 0x7f) )
{
return(0);/* Bad character in filename */
}
}

/*
* This appears to be a MacBinary header. See if it's for a Screen-image
* file.
*/

if ( memcmp( &p->finder_info.file_type[0], "SCRN", 4 ) == 0 )
{
return(1);/* It is */
}

return(2);/* Call it a normal file */
}



/*
* Examine file whose data starts at p, to see if it is an RLE file. If so,
* then decode it as such into mem_image.
*
* Returns: -1 if this is an RLE file, and we've handled it
* 0 if this is not an RLE file
*/

isrle(p, eof)
BYTE *p;/* First byte of file's data */
BYTE *eof;/* Physical end of file */
{
BYTE c0, c1, c2;
unsigned line, col, horiz, vert;

#if DEBUG
long start;/* Time at start of decode */
#endif


c0 = (*p++) & 0x7f;/* Get first three bytes of file */
c1 = (*p++) & 0x7f;
c2 = (*p++) & 0x7f;

/*
* An RLE file starts with:
*
* G MMedium resolution (128 x 96) file
*or
* G HHigh resolution (256 x 192) file
*/

if ( (c0 != 0x1b) || (c1 != 'G') || ( (c2 != 'H') && (c2 != 'M') ) )
{
return(0);/* Not an RLE file */
}

/*
* Figure out where on screen to put this RLE image
*/

line = RLE_LINE( rle_pic % 6 );
col = RLE_COL( rle_pic % 6 );

if ( c2 == 'H' )
{
horiz = 256;
vert = 192;
}
else
{
horiz = 128;
vert = 96;
}

rle_horiz[ rle_pic % 6 ] = horiz;/* Save dimensions of this image */
rle_vert[ rle_pic % 6 ] = vert;

if ( rle_pic++ == 0 ) /* Any RLE images on screen? */
{
memset(mem_image,fill_type,sizeof(mem_image));/* No, init the screen */
}


#if DEBUG
start = ticker();/* Remember time at start of decoding */
#endif

do_rle( p, line, col, eof, horiz, vert );/* Decode the data */

#if DEBUG
elapsed[next_elapsed++] =/* Calc duration of decode */
ticker() - start;
#endif

return(-1);/* It's an RLE file */
}




/*
* Decode RLE data starting at p, into a rectangle with upper-left corner
* at mem_image[line][col]. The end of the image is marked by "p >= eof", or
* by the appearance of " G N" within the data stream, or by running
* outside of the bounds of the rectangle with is "horiz" x "vert" pixels
* in size (both guaranteed to be evan multiples of 8).
*/

do_rle( p, line, col, eof, horiz, vert )
register BYTE *p;
unsigned line, col;
BYTE *eof;
unsigned horiz, vert;
{
static BYTE *NEARmem;/* Pointer to target mem_image byte */

static BYTENEARfg,/* Non-zero if we're doing foreground */
NEARc,/* One byte */
NEARbit,/* For addressing one bit within a byte */
NEARleftover;/* Leftover pixels from previous line */

static unsigned NEARpixel,/* What "horiz" pixel we're on */
NEAR max_done,/* Total pixels that can be in file */
NEAR num_done;/* Number of pixels we've actually done */

static intNEARi;

static BYTENEARpixels[8] =
{
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};

/*
* Clear out the rectangle for our image. The following code assumes
* that the background in already black, so we'd better set it that way.
*/

mem = &mem_image[line][col];
pixel = horiz >> 3;/* Temporary (fast) version of this */

for ( i = 0; i < vert; i++ )
{
memset( mem, 0, pixel );
mem += (MAC_HORIZ/8);/* Up to next subline */
}

fg = 0;/* First data byte is for background */
max_done = horiz * vert;/* Calc total bytes to be done */
num_done = 0;/* We've done none so far */
pixel = 0;/* Start at left edge */
leftover = 0;

while ( p < eof )
{
mem = &mem_image[line][col+(pixel/8)];/* Make sure that we're in sync */

if ( leftover )/* Anything leftover from previous count? */
{
c = leftover;/* Yes, use it */
leftover = 0;/* And clear it */
}
else
{
c = (*p++) & 0x7f;/* Get next data byte */

if ( c < 0x20 )
{

/*
* We have a control character. If this
* is the start of our " G N" eof
* string, then obey it. Else ignore all
* control characters.
*/

if ( c == 0x1e )/* ESCAPE? */
{
if ( ((*p & 0x7f) == 'G') && ((*(p+1) & 0x7f) == 'N') )
{
break;/* Found " G N" */
}
}

continue;/* Go get next char */
}

c -= 0x20;/* Convert to pixel count */
}

/*
* Things go a lot quicker if we know that we won't overflow one
* line. So truncate c to fill out our line, putting any excess
* into "leftover". We'll come back and service it on the next pass.
*/

if ( ( (unsigned) c + pixel ) >= horiz )
{
leftover = ( ((unsigned) c + pixel) - horiz );
c = horiz - pixel;
}

num_done += (unsigned) c;

/*
* If we're doing foreground, then we must plot pixels.
* If doing background, we can just skip ahead as many
* pixels as c says to.
*/

if (fg)
{

/*
* We're plotting foreground
*/

bit = 0;/* Fill up to next byte boundary */

while ( c && (pixel & 7) )
{
bit |= pixels[(pixel++) & 7];
c--;
}

if ( bit )
{
*mem++ |= bit;
}

/*
* We can now advance great gobs (8 pixels, to be precise)
* at a time. This is a lot faster than doing 1 pixel at a time.
*/

pixel += (c & 0xf8);

while ( c >= 8 )/* While at least 8 pixels left... */
{
*mem++ = 0xff;/* ...just zap a bunch of 1's there */
c -= 8;/* Count that many fewer to do */
}

/*
* Done with great-gobbing 8 pixels at once. Now
* slow down and do one at a time for this last byte.
*/

bit = 0;

while ( c-- )/* Build mask of bits to turn on */
{
bit |= pixels[(pixel++) & 7];
}

*mem |= bit;
}
else

{

/*
* We're just skipping pixels, cause we're in background
* color.
*/

pixel += c;
}

/*
* Check for next line
*/

if ( num_done >= max_done )
{
break;/* We've done whole image */
}

if ( leftover || (pixel >= horiz) )
{

/*
* Move to next line
*/

if ( --vert == 0 )
{
break;/* We've left last line */
}

line++;/* Move to next line */
pixel = 0;
}

/*
* If any leftover, then stay in same fg/bg mode. Else
* change modes cause next data character represents
* the number of pixels of the opposite color.
*/

if ( !leftover )
{
fg ^= 1;
}
}
}






/*
* Convert MACPAINT encoded data at "in" to our MAC_VERT x MAC_HORIZ pixel array.
*
* Normally, a MACPAINT file has exactly 720 lines defined, even if they're all
* blank. We have encountered some, however, that are truncated at the end
* of the actual image, even if a full 720 lines haven't been defined. This
* may cause leftover data bytes in scratch[] to be decoded as if they belonged
* to this file.
*
* To solve this, we pass to this routine a pointer to the physical end of
* file. If we ever wind up decoding lines beyond this, we know that we have
* got a truncated file. So we fill the rest of mem_image[] with the default
* fill pattern.
*
*/

get_mem_image(in, eof)
register BYTE *in;
register BYTE *eof;/* Pointer to physical end of file */
{
int line;/* What line # we're doing */
int i;

for ( line = 0; line < MAC_VERT; line++ )
{
if ( in >= eof )
{

/*
* We have run off end of the physical file. This
* must be a truncated file. Fill rest of lines
* with the default fill type.
*/

memset( &mem_image[end_of_image = line][0], fill_type, ( (MAC_VERT) - line ) * (MAC_HORIZ/8) );
return;
}

/*
* Get another line from input, per data_type
*/

if ( data_type == ENCODED )
{
in = decode(in, &mem_image[line][0]);
}
else
{

/*
* The file's data is just a raw image. So copy
* whatever's there to our array. Since the raw data
* is only 64 bytes long, pad out our 72-byte line with
* the default fill pattern.
*/

memset( &mem_image[line][0], fill_type, 4 );
memset( &mem_image[line][68], fill_type, 4 );
memcpy( &mem_image[line][4], in, 64 );
in += 64;
}
}

end_of_image = MAC_VERT;/* If we got here, it's a full screen */
}


/*
* Decode one MACPAINT line whose byte is at "in", putting the
* decoded output data into "out".
*
* Returns new, advanced value of "in".
*/

BYTE *decode(in, out)
register BYTE *in;
register BYTE *out;
{
register int count;/* Our count byte */
unsigned num_out;/* How many output bytes we've done */

num_out = 0;

while( num_out < (MAC_HORIZ/8) )/* Till we've output 72 bytes (576 pixels) */
{
count = *in++; /* Get byte */

if ( count & 0x80 )
{

/*
* This is a repeated byte pattern. Output
* +1 copies of next byte.
*/

count |= 0xff00;/* Negate count */
count = (0 - count) + 1;
memset(out, *in++, count);/* Dupe that many times */
}
else
{

/*
* This is a simple string of bytes to copy.
*/

count++;
memcpy( out, in, count );
in += count;
}

out += count;/* Advance output past data bytes */
num_out += count;/* This many more output bytes done */
}

return(in);/* Return advanced pointer */
}





 December 7, 2017  Add comments

Leave a Reply