home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
graf
/
macpnt1.zip
/
WRITEMAC.C
< prev
Wrap
Text File
|
1987-01-16
|
11KB
|
413 lines
/*
*************************************************************
* WRITEMAC.C - routines to handle writing of image as a MacPaint
* file.
*
* (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.
*
*************************************************************
*/
/*
* Write current picture to a disk file. The thing is written with
* a MacBinary header, and in theory should be in a format that even
* allows it to be read by a Mac. Our immediate concern, however, is
* just to get it in a format that this program will recognize if it
* is ever told to read it again.
*
* First we write a preface (the MacBinary and MacPaint headers), and
* then the data, and then - after we know how many bytes of data we
* have - we rewrite the preface with the data_fork_size set to the
* number of bytes in the data.
*/
writemac()
{
int handle; /* Of file being written to */
unsigned size; /* # bytes of data */
static struct _macpaint preface; /* Our file's preface */
static BYTE filename[256];
/*
* Get Mac filename to write with the MacBinary header
*/
mode(TEXT);
fprintf(stderr, "\nEnter the Macintosh name for this picture. This is NOT");
fprintf(stderr, "\nthe DOS filename, but is the name that would be used");
fprintf(stderr, "\nto create the file on the Mac. Up to 63 characters:\n\n");
gets(filename);
if ( strlen(filename) < 1 ) /* Did he enter a name? */
{
strcpy(filename, "JR file"); /* No, give it one */
}
filename[63] = 0; /* Truncate in case it's too large */
/*
* Make our preface presentable
*/
memset( &preface, 0, sizeof( struct _macpaint ) );
strcpy( preface.macbinary_header.filename, filename );
preface.macbinary_header.name_size = strlen(filename);
strcpy( preface.macbinary_header.finder_info.file_type, "PNTGMPNT" );
preface.macbinary_header.finder_info.flags = 1;
memcpy( preface.macbinary_header.create_date, "\x9b\x63\xed\x00\x9b\x63\xed\x00", 8 );
memset( &preface.header.patterns[0][0], 0xff, 38 * 8 );
preface.header.version = 0x02000000L;
/*
* Now get DOS filename to write
*/
fprintf(stderr, "\n\nDOS file to write it to:\n\n");
gets(filename);
if ( strlen(filename) < 1 ) /* Did he enter a name? */
{
return; /* No, skip it */
}
/*
* Open the DOS file
*/
handle = open(filename, O_CREAT | O_TRUNC | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD );
if ( (handle != -1) && isatty(handle) )
{
close(handle); /* Don't allow writes to char devices */
handle = -1;
}
if ( handle == -1 )
{
fprintf(stderr, "\n\nCan't open file '%s'!\nPress RETURN...", filename );
key();
return;
}
/*
* Write our preface, then true data to file
*/
if ( write( handle, &preface, (sizeof(struct _macpaint) - 1) ) != (sizeof(struct _macpaint) - 1) )
{
failed:
close(handle);
fprintf(stderr, "\n\nError writing to file '%s'!\nPress RETURN...", filename );
key();
return;
}
if ( (size = write_pic(handle)) == 0 )
{
goto failed;
}
size += sizeof(struct _header); /* Include MacPaint header in size */
/*
* Rewrite preface with proper data_fork size
*/
if ( lseek( handle, 0L, 0 ) == -1L )
{
goto failed;
}
preface.macbinary_header.data_fork_length = ( ((long) size & 0xff) << 24 ) | ( ((long) size & 0xff00) << 8 );
if ( write( handle, &preface, (sizeof(struct _macpaint) - 1) ) != (sizeof(struct _macpaint) - 1) )
{
goto failed;
}
/*
* All went well
*/
close(handle);
}
/*
* Write out entire mem_image to "handle" (which has already been opened
* for output).
*
* We try to compress the image according to the rules for MacPaint
* repeat compression, by examining the data as it is written and
* reducing bytes that occur 3 or more times in succession to
* a 2-byte encoded form.
*
* Returns: 0 if error writing to file, else number of actual data bytes
* written to the file.
*
*/
unsigned write_pic(handle)
int handle; /* Handle of an already-opened file to write to */
{
static BYTE repeat_buf[ (MAC_HORIZ/8) + 1 ];
static BYTE outbuf[ (MAC_HORIZ/8) * 2 ];
BYTE * p;
int outsize, /* # output bytes to write to file */
repeat_count, /* # repetitions of a repeated byte */
repeat_index, /* Offset into repeat_buf */
next_repeat, /* The next repeat count after ours */
line; /* What line of image we're doing */
unsigned total_out; /* Total number of bytes written to file */
/*
* Examine, encode, and write out each line as a separate entity
*/
p = &mem_image[0][0]; /* Start at at front of image */
total_out = 0; /* No bytes written yet */
for ( line = 0; line < MAC_VERT; line++ )
{
/*
* Examine this line, and get array of repeat counts into
* repeat_buf
*/
outscan(p, repeat_buf);
/*
* Decode repeat counts, using analysis thereof to determine
* which bytes get written as simple images and which ones
* get written as encoded repeat patterns.
*/
outsize = 0; /* At front of output buffer */
repeat_index = 0; /* At front of repeat list too */
while( repeat_count = repeat_buf[repeat_index++] )
{
if ( repeat_count < 3 )
{
/*
* This is a straight copy, 'cause this byte
* doesn't occur enough times in a row to
* warrant an encoded form. Since we're
* copying verbatim anyway, we may as well
* include anybody immediately following us
* who is likewise just a straight copy (i.e. -
* whose repeat count is less than 3).
*/
while( next_repeat = repeat_buf[ repeat_index ] )
{
/*
* If this next repeat count is >= 3,
* then he deserves encoding. So don't
* swallow him into this straight-copy mess.
*/
if ( next_repeat >= 3 )
{
break;
}
/*
* Otherwise just add his paltry repeat count
* to however many bytes we're already
* gonna copy directly.
*/
repeat_count += next_repeat;
repeat_index++;
}
/*
* We now know how many total bytes deserve to
* be copied directly. Do it.
*/
outbuf[ outsize++ ] = repeat_count - 1; /* Use positive repeat count */
memcpy( &outbuf[outsize], p, repeat_count );
/*
* Advance everybody over the bytes that we
* just copied.
*/
p += repeat_count;
outsize += repeat_count;
}
else
{
/*
* This repeat count is 3 or more. It is
* worth encoding into a 2-byte repeat sequence.
*/
outbuf[ outsize++ ] = 0 - (repeat_count - 1); /* Use negative repeat count */
outbuf[ outsize++ ] = *p;
/*
* Skip over all repeated bytes in input
*/
p += repeat_count;
}
}
/*
* We're done with this line. Write it to the file.
*/
if ( write(handle, outbuf, outsize) != outsize )
{
return(0); /* Error writing file */
}
total_out += outsize; /* Bump total written */
}
/*
* Fill out the last 512-byte Mac sector, for no reason other than that
* the files that we've seen seem to have this done.
*/
outsize = sizeof(outbuf);
memset( outbuf, 0, outsize );
repeat_count = 512 - (total_out & 511); /* Re-use a stray variable! */
while( repeat_count )
{
if ( repeat_count < outsize ) /* Almost done? */
{
outsize = repeat_count; /* Yes, fine-tune it */
}
repeat_count -= outsize; /* Update stats first */
total_out += outsize;
if ( write(handle, outbuf, outsize) != outsize )
{
return(0); /* Bad write */
}
}
return(total_out); /* No errors */
}
/*
* Examine 72-byte MacPaint line at "in", and from it build (at "out")
* a list of the repeated-byte string lengths contained in it. Each
* byte of "out" holds a count of the number of identical bytes that
* were found. The "out" array is terminated with a NUL byte.
*
* Example: in = "TESST"
* out = 1,1,2,1,NUL
*
* Worst case (from a compression standpoint) will result in "out" holding
* 72 bytes (each of which has the binary value 1), plus the terminating
* NUL:
*
* 1,1,1,1,1,1,1,...1,1,1,1,1,NUL
*
* Best case yields "out" of one byte (plus the NUL):
*
* 72,NUL
*
* This is all part of our desire to compress the output as much as
* possible. It may or may not make sense on a Mac. But it does produce
* output that is acceptable to this program when it's read back in.
*
*/
outscan(in, out)
BYTE *in; /* Raw MacPaint line */
BYTE *out; /* Where to put repeat list */
{
register int i, /* Scratch */
count; /* Repeat count for current string */
int byte; /* What byte number we're doing (0-71) */
BYTE val; /* Value of current byte */
/*
* Scan through all 72 bytes of this line
*/
byte = 0; /* Start at the front */
while ( byte < (MAC_HORIZ/8) )
{
i = byte + 1; /* First potential repeat */
count = 1; /* We're at least 1 long already! */
val = in[byte]; /* What to compare next bytes to */
/*
* See how many subsequent bytes are the same as this one
*/
while( (i < (MAC_HORIZ/8)) && ( in[i++] == val ) )
{
count++; /* Got another hit! */
}
/*
* Store this repeat count into "out", and advance over that
* many input bytes.
*/
*out++ = count;
byte += count;
}
*out = 0; /* NUL-terminate "out" */
}