home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / graf / macpnt1.zip / READMAC.C < prev    next >
Text File  |  1987-01-16  |  16KB  |  687 lines

  1.  
  2.  
  3.  
  4. /*
  5.  ***************************************************************
  6.  * READMAC.C - routines to read in and decode MacPaint and RLE files
  7.  *
  8.  * (c) Copyright 1987 by:
  9.  *
  10.  *          Computerwise Consulting Services
  11.  *          P.O. Box 813
  12.  *          McLean, VA 22101
  13.  *          (703) 280-2809
  14.  *
  15.  * All rights reserved.
  16.  *
  17.  * Permission is granted for personal use of this program, with the
  18.  * exception that the following potential users ARE EXPLICITLY DENIED
  19.  * PERMISSION TO RECEIVE, USE, OR TRANSFER THIS PROGRAM IN SOURCE OR
  20.  * OBJECT OR EXECUTABLE OR ANY OTHER FORM:
  21.  *
  22.  *     1) Lotus Development Corporation, and any employee thereof
  23.  *        or consultant thereto;
  24.  *
  25.  *     2) ADAPSO, and any firm which is a member thereof, or any
  26.  *        employee of such a firm.
  27.  *
  28.  * These two organizations have - in the opinion of CCS - acted as
  29.  * "software pirates" by continually and intentionally violating
  30.  * U.S. Copyright law, specifically by first "copy-protecting" software
  31.  * disks and then zealously prosecuting innocent users who exercised
  32.  * their rights under the law to make copies of their own property.
  33.  *
  34.  * Further, permission is granted to transfer this program only if
  35.  * it is transferred absolutely unmodified in any form.
  36.  *
  37.  ***************************************************************
  38.  */
  39.  
  40.  
  41. /*
  42.  * Read MACPAINT file "fname" into mem_array.
  43.  *
  44.  * Returns -1 if error, else zero.
  45.  */
  46.  
  47. readmac(fname)
  48. BYTE *fname;                /* Filename to open */
  49. {
  50.     BYTE *eof;            /* Pointer to physical EOF */
  51.     BYTE *p;
  52.     int handle, num_read;
  53.  
  54. #if DEBUG
  55.     long start;            /* Time at start of decode */
  56. #endif
  57.  
  58.     handle = open(fname, O_RDONLY | O_BINARY);
  59.  
  60.     if (handle == -1)
  61.         {
  62.         return(-1);        /* Can't open file */
  63.         }
  64.  
  65.     if ( isatty(handle) )
  66.         {
  67.         close(handle);
  68.         return(-1);        /* Don't get smart! */
  69.         }
  70.  
  71.     /*
  72.      * Read in all data
  73.      */
  74.  
  75.     num_read = read(handle, scratch, sizeof(scratch));
  76.     close(handle);
  77.  
  78.     if ( num_read == -1 )
  79.         {
  80.         return(-1);            /* Bad read */
  81.         }
  82.  
  83.     eof = scratch;                /* Set physical EOF */
  84.     eof += (unsigned) num_read;
  85.  
  86.     /*
  87.      * Find start of actual data (skipping MacBinary and/or MacPaint headers)
  88.      */
  89.  
  90.     p = adjust(scratch);
  91.  
  92.     /*
  93.      * If this is an RLE file, now's the time to find that out and
  94.      * decode it as such.
  95.      */
  96.  
  97.     if ( isrle(p, eof) )
  98.         {
  99.  
  100.         if ( auto_invert )                /* Are we inverting things? */
  101.             {
  102.             invert_rle( (rle_pic + 5) % 6 );    /* Yes, invert this RLE image */
  103.             }
  104.  
  105.         /*
  106.          * If this has filled our screen with the 6th RLE image, then
  107.          * flush it to the screen or the printer.
  108.          */
  109.  
  110.         if ( rle_pic >= 6 )
  111.             {
  112.             flush();
  113.             rle_pic = 0;
  114.             }
  115.  
  116.         return(0);        /* No errors, it's been decoded */
  117.         }
  118.  
  119.     /*
  120.      * This is not an RLE image. However, we may have buffered up some
  121.      * RLE files prior to this non-RLE file which have yet to be
  122.      * displayed or printed. We had better display/print them now, 'cause
  123.      * we're about to overwrite the image with our new MacPaint file!
  124.      */
  125.  
  126.     if ( rle_pic )            /* Got any RLE images? */
  127.         {
  128.         flush();        /* Yes, display or print them */
  129.         rle_pic = 0;        /* We ain't got them no more! */
  130.         }
  131.  
  132.     /*
  133.      * Now decode it as a MacPaint file into mem_image
  134.      */
  135.  
  136. #if DEBUG
  137.     start = ticker();        /* Remember time at start of decoding */
  138. #endif
  139.  
  140.     get_mem_image(p, eof);        /* Decode picture */
  141.  
  142. #if DEBUG
  143.     elapsed[next_elapsed++] =    /* Calc duration of decode */
  144.         ticker() - start;
  145. #endif
  146.  
  147.  
  148.     /*
  149.      * And automatically display or print it
  150.      */
  151.  
  152.     if ( auto_invert )        /* Are we inverting things? */
  153.         {
  154.         invert();        /* Yes, invert this image */
  155.         }
  156.  
  157.     flush();
  158.     return(0);
  159. }
  160.  
  161.  
  162. /*
  163.  * Given a pointer p to the start of the in-memory image of a MACPAINT
  164.  * file, return a pointer to the first actual data byte.
  165.  *
  166.  * Some MACPAINT files include the MacBinary header up front. Others don't.
  167.  * All should have at least the MacPaint header. It all depends on
  168.  * the person that did the uploading.
  169.  *
  170.  * It is this routine's job to deduce the presence of any prologue,
  171.  * and return a pointer that skips over it. It must also set data_type
  172.  * to either ENCODED or RAW, per the file's format.
  173.  */
  174.  
  175. BYTE *adjust(p)
  176. BYTE *p;
  177. {
  178.  
  179.     data_type = ENCODED;            /* Assume ENCODED, cause most files are */
  180.  
  181.     /*
  182.      * Check for 32-bit MacPaint or FullPaint version as first thing in file
  183.      * (i.e. - no MacBinary header).
  184.      *
  185.      * NOTE: Some files that we have seen have a dummy 512-byte header
  186.      *       of zeroes. All that we can figure is that somebody got ahold
  187.      *       of a bunch of raw data, and needed to prepend some kind
  188.      *       of header so that it would be readable as a MACPAINT file.
  189.      *       This dummy 512-byte header of zeroes serves as the brush/pattern
  190.      *       header. Although this following test doesn't specifically
  191.      *       check for 512 bytes of zeroes at the front, such a zero
  192.      *       header WILL be caught by this test, and will cause us to
  193.      *       skip the first 512 bytes of the file. So all comes out right
  194.      *       after all...
  195.      */
  196.  
  197.     if ( (p[0] == 0) && (p[1] == 0) && (p[2] == 0) && (p[3] < 5) )
  198.         {
  199.         return(p + 512);        /* File starts with MacPaint header info */
  200.         }
  201.  
  202.     /*
  203.      * Check for MacBinary header at front of file
  204.      */
  205.  
  206.     switch ( ismacbin(p) )
  207.         {
  208.         case 0:                /* Not a MacBinary header, so assume all data */
  209.             return(p);
  210.  
  211.         case 1:                /* Screen Image (like StartupScreen) */
  212.             data_type = RAW;
  213.             return(p + 128);
  214.  
  215.         case 2:                /* Normal file with MacBinary and MacPaint headers */
  216.             return( p + 640 );
  217.         }
  218. }
  219.  
  220.  
  221.  
  222. /*
  223.  * Examine potential MacBinary header at p, and return code describing it:
  224.  *
  225.  *    0 = not a MacBinary header
  226.  *    1 = file is Screen Image (RAW)
  227.  *    2 = file is standard MacPaint file (ENCODED)
  228.  */
  229.  
  230. ismacbin(p)
  231. register struct _macbinary_header *p;
  232. {
  233.     int i;
  234.     unsigned u;
  235.  
  236.     u = p->name_size;
  237.  
  238.     if (
  239.         (u > 63) ||            /* If bad name size... */
  240.         (u == 0) ||
  241.         (p->zero != 0) ||        /* ...or zero bytes aren't zero... */
  242.         (p->finder_info.zero != 0) ||
  243.         (p->version > 1)        /* ...or odd version */
  244.        )
  245.         {
  246.         return(0);            /* Not a MacBinary header */
  247.         }
  248.  
  249.     /*
  250.      * Verify that the filename is all legal ASCII characters
  251.      */
  252.  
  253.     for ( i = 0; i < u; i++ )
  254.         {
  255.         if ( (p->filename[i] < ' ') || (p->filename[i] > 0x7f) )
  256.             {
  257.             return(0);        /* Bad character in filename */
  258.             }
  259.         }
  260.  
  261.     /*
  262.      * This appears to be a MacBinary header. See if it's for a Screen-image
  263.      * file.
  264.      */
  265.  
  266.     if ( memcmp( &p->finder_info.file_type[0], "SCRN", 4 ) == 0 )
  267.         {
  268.         return(1);            /* It is */
  269.         }
  270.  
  271.     return(2);                /* Call it a normal file */
  272. }
  273.  
  274.  
  275.  
  276. /*
  277.  * Examine file whose data starts at p, to see if it is an RLE file. If so,
  278.  * then decode it as such into mem_image.
  279.  *
  280.  * Returns:  -1 if this is an RLE file, and we've handled it
  281.  *            0 if this is not an RLE file
  282.  */
  283.  
  284. isrle(p, eof)
  285. BYTE *p;            /* First byte of file's data */
  286. BYTE *eof;            /* Physical end of file */
  287. {
  288.     BYTE c0, c1, c2;
  289.     unsigned line, col, horiz, vert;
  290.  
  291. #if DEBUG
  292.     long start;        /* Time at start of decode */
  293. #endif
  294.  
  295.  
  296.     c0 = (*p++) & 0x7f;    /* Get first three bytes of file */
  297.     c1 = (*p++) & 0x7f;
  298.     c2 = (*p++) & 0x7f;
  299.  
  300.     /*
  301.      * An RLE file starts with:
  302.      *
  303.      *    <ESC> G M    Medium resolution (128 x 96) file
  304.      *    or
  305.      *    <ESC> G H    High resolution (256 x 192) file
  306.      */
  307.  
  308.     if ( (c0 != 0x1b) || (c1 != 'G') || ( (c2 != 'H') && (c2 != 'M') ) )
  309.         {
  310.         return(0);    /* Not an RLE file */
  311.         }
  312.  
  313.     /*
  314.      * Figure out where on screen to put this RLE image
  315.      */
  316.  
  317.     line = RLE_LINE( rle_pic % 6 );
  318.     col = RLE_COL( rle_pic % 6 );
  319.  
  320.     if ( c2 == 'H' )
  321.         {
  322.         horiz = 256;
  323.         vert = 192;
  324.         }
  325.     else
  326.         {
  327.         horiz = 128;
  328.         vert = 96;
  329.         }
  330.  
  331.     rle_horiz[ rle_pic % 6 ] = horiz;            /* Save dimensions of this image */
  332.     rle_vert[ rle_pic % 6 ] = vert;
  333.  
  334.     if ( rle_pic++ == 0 )                     /* Any RLE images on screen? */
  335.         {
  336.         memset(mem_image,fill_type,sizeof(mem_image));    /* No, init the screen */
  337.         }
  338.  
  339.  
  340. #if DEBUG
  341.     start = ticker();                    /* Remember time at start of decoding */
  342. #endif
  343.  
  344.     do_rle( p, line, col, eof, horiz, vert );        /* Decode the data */
  345.  
  346. #if DEBUG
  347.     elapsed[next_elapsed++] =                /* Calc duration of decode */
  348.         ticker() - start;
  349. #endif
  350.  
  351.     return(-1);                        /* It's an RLE file */
  352. }
  353.  
  354.  
  355.  
  356.  
  357. /*
  358.  * Decode RLE data starting at p, into a rectangle with upper-left corner
  359.  * at mem_image[line][col]. The end of the image is marked by "p >= eof", or
  360.  * by the appearance of "<ESC> G N" within the data stream, or by running
  361.  * outside of the bounds of the rectangle with is "horiz" x "vert" pixels
  362.  * in size (both guaranteed to be evan multiples of 8).
  363.  */
  364.  
  365. do_rle( p, line, col, eof, horiz, vert )
  366. register BYTE *p;
  367. unsigned line, col;
  368. BYTE *eof;
  369. unsigned horiz, vert;
  370. {
  371.     static BYTE *    NEAR    mem;            /* Pointer to target mem_image byte */
  372.  
  373.     static BYTE    NEAR    fg,            /* Non-zero if we're doing foreground */
  374.             NEAR    c,            /* One byte */
  375.             NEAR    bit,            /* For addressing one bit within a byte */
  376.             NEAR    leftover;        /* Leftover pixels from previous line */
  377.  
  378.     static unsigned NEAR    pixel,            /* What "horiz" pixel we're on */
  379.             NEAR     max_done,        /* Total pixels that can be in file */
  380.             NEAR     num_done;        /* Number of pixels we've actually done */
  381.  
  382.     static int    NEAR    i;
  383.  
  384.     static BYTE    NEAR    pixels[8] =
  385.         {
  386.         0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
  387.         };
  388.  
  389.     /*
  390.      * Clear out the rectangle for our image. The following code assumes
  391.      * that the background in already black, so we'd better set it that way.
  392.      */
  393.  
  394.     mem = &mem_image[line][col];
  395.     pixel = horiz >> 3;        /* Temporary (fast) version of this */
  396.  
  397.     for ( i = 0; i < vert; i++ )
  398.         {
  399.         memset( mem, 0, pixel );
  400.         mem += (MAC_HORIZ/8);    /* Up to next subline */
  401.         }
  402.  
  403.     fg = 0;                /* First data byte is for background */
  404.     max_done = horiz * vert;    /* Calc total bytes to be done */
  405.     num_done = 0;            /* We've done none so far */
  406.     pixel = 0;            /* Start at left edge */
  407.     leftover = 0;
  408.  
  409.     while ( p < eof )
  410.         {
  411.         mem = &mem_image[line][col+(pixel/8)];    /* Make sure that we're in sync */
  412.  
  413.         if ( leftover )                /* Anything leftover from previous count? */
  414.             {
  415.             c = leftover;            /* Yes, use it */
  416.             leftover = 0;            /* And clear it */
  417.             }
  418.         else
  419.             {
  420.             c = (*p++) & 0x7f;        /* Get next data byte */
  421.  
  422.             if ( c < 0x20 )
  423.                 {
  424.  
  425.                 /*
  426.                  * We have a control character. If this
  427.                  * is the start of our "<ESC> G N" eof
  428.                  * string, then obey it. Else ignore all
  429.                  * control characters.
  430.                  */
  431.  
  432.                 if ( c == 0x1e )    /* ESCAPE? */
  433.                     {
  434.                     if ( ((*p & 0x7f) == 'G') && ((*(p+1) & 0x7f) == 'N') )
  435.                         {
  436.                         break;    /* Found "<ESC> G N" */
  437.                         }
  438.                     }
  439.  
  440.                 continue;        /* Go get next char */
  441.                 }
  442.  
  443.             c -= 0x20;            /* Convert to pixel count */
  444.             }
  445.  
  446.         /*
  447.          * Things go a lot quicker if we know that we won't overflow one
  448.          * line. So truncate c to fill out our line, putting any excess
  449.          * into "leftover". We'll come back and service it on the next pass.
  450.          */
  451.  
  452.         if ( ( (unsigned) c + pixel ) >= horiz )
  453.             {
  454.             leftover = ( ((unsigned) c + pixel) - horiz );
  455.             c = horiz - pixel;
  456.             }
  457.  
  458.         num_done += (unsigned) c;
  459.  
  460.         /*
  461.          * If we're doing foreground, then we must plot pixels.
  462.          * If doing background, we can just skip ahead as many
  463.          * pixels as c says to.
  464.          */
  465.  
  466.         if (fg)
  467.             {
  468.  
  469.             /*
  470.              * We're plotting foreground
  471.              */
  472.  
  473.             bit = 0;        /* Fill up to next byte boundary */
  474.  
  475.             while ( c && (pixel & 7) )
  476.                 {
  477.                 bit |= pixels[(pixel++) & 7];
  478.                 c--;
  479.                 }
  480.  
  481.             if ( bit )
  482.                 {
  483.                 *mem++ |= bit;
  484.                 }
  485.  
  486.             /*
  487.              * We can now advance great gobs (8 pixels, to be precise)
  488.              * at a time. This is a lot faster than doing 1 pixel at a time.
  489.              */
  490.  
  491.             pixel += (c & 0xf8);
  492.  
  493.             while ( c >= 8 )    /* While at least 8 pixels left... */
  494.                 {
  495.                 *mem++ = 0xff;    /* ...just zap a bunch of 1's there */
  496.                 c -= 8;        /* Count that many fewer to do */
  497.                 }
  498.  
  499.             /*
  500.              * Done with great-gobbing 8 pixels at once. Now
  501.              * slow down and do one at a time for this last byte.
  502.              */
  503.  
  504.             bit = 0;
  505.  
  506.             while ( c-- )        /* Build mask of bits to turn on */
  507.                 {
  508.                 bit |= pixels[(pixel++) & 7];
  509.                 }
  510.  
  511.             *mem |= bit;
  512.             }
  513.         else
  514.             {
  515.  
  516.             /*
  517.              * We're just skipping pixels, cause we're in background
  518.              * color.
  519.              */
  520.  
  521.             pixel += c;
  522.             }
  523.  
  524.         /*
  525.          * Check for next line
  526.          */
  527.  
  528.         if ( num_done >= max_done )
  529.             {
  530.             break;            /* We've done whole image */
  531.             }
  532.  
  533.         if ( leftover || (pixel >= horiz) )
  534.             {
  535.  
  536.             /*
  537.              * Move to next line
  538.              */
  539.  
  540.             if ( --vert == 0 )
  541.                 {
  542.                 break;        /* We've left last line */
  543.                 }
  544.  
  545.             line++;            /* Move to next line */
  546.             pixel = 0;
  547.             }
  548.  
  549.         /*
  550.          * If any leftover, then stay in same fg/bg mode. Else
  551.          * change modes cause next data character represents
  552.          * the number of pixels of the opposite color.
  553.          */
  554.  
  555.         if ( !leftover )
  556.             {
  557.             fg ^= 1;
  558.             }
  559.         }
  560. }
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567. /*
  568.  * Convert MACPAINT encoded data at "in" to our MAC_VERT x MAC_HORIZ pixel array.
  569.  *
  570.  * Normally, a MACPAINT file has exactly 720 lines defined, even if they're all
  571.  * blank. We have encountered some, however, that are truncated at the end
  572.  * of the actual image, even if a full 720 lines haven't been defined. This
  573.  * may cause leftover data bytes in scratch[] to be decoded as if they belonged
  574.  * to this file.
  575.  *
  576.  * To solve this, we pass to this routine a pointer to the physical end of
  577.  * file. If we ever wind up decoding lines beyond this, we know that we have
  578.  * got a truncated file. So we fill the rest of mem_image[] with the default
  579.  * fill pattern.
  580.  *
  581.  */
  582.  
  583. get_mem_image(in, eof)
  584. register BYTE *in;
  585. register BYTE *eof;            /* Pointer to physical end of file */
  586. {
  587.     int line;            /* What line # we're doing */
  588.     int i;
  589.  
  590.     for ( line = 0; line < MAC_VERT; line++ )
  591.         {
  592.         if ( in >= eof )
  593.             {
  594.  
  595.             /*
  596.              * We have run off end of the physical file. This
  597.              * must be a truncated file. Fill rest of lines
  598.              * with the default fill type.
  599.              */
  600.  
  601.             memset( &mem_image[end_of_image = line][0], fill_type, ( (MAC_VERT) - line ) * (MAC_HORIZ/8) );
  602.             return;
  603.             }
  604.  
  605.         /*
  606.          * Get another line from input, per data_type
  607.          */
  608.  
  609.         if ( data_type == ENCODED )
  610.             {
  611.             in = decode(in, &mem_image[line][0]);
  612.             }
  613.         else
  614.             {
  615.  
  616.             /*
  617.              * The file's data is just a raw image. So copy
  618.              * whatever's there to our array. Since the raw data
  619.              * is only 64 bytes long, pad out our 72-byte line with
  620.              * the default fill pattern.
  621.              */
  622.  
  623.             memset( &mem_image[line][0], fill_type, 4 );
  624.             memset( &mem_image[line][68], fill_type, 4 );
  625.             memcpy( &mem_image[line][4], in, 64 );
  626.             in += 64;
  627.             }
  628.         }
  629.  
  630.     end_of_image = MAC_VERT;        /* If we got here, it's a full screen */
  631. }
  632.  
  633.  
  634. /*
  635.  * Decode one MACPAINT line whose <count> byte is at "in", putting the
  636.  * decoded output data into "out".
  637.  *
  638.  * Returns new, advanced value of "in".
  639.  */
  640.  
  641. BYTE *decode(in, out)
  642. register BYTE *in;
  643. register BYTE *out;
  644. {
  645.     register int count;                /* Our count byte */
  646.     unsigned num_out;                /* How many output bytes we've done */
  647.  
  648.     num_out = 0;
  649.  
  650.     while( num_out < (MAC_HORIZ/8) )        /* Till we've output 72 bytes (576 pixels) */
  651.         {
  652.         count = *in++;                 /* Get <count> byte */
  653.  
  654.         if ( count & 0x80 )
  655.             {
  656.  
  657.             /*
  658.              * This is a repeated byte pattern. Output
  659.              * <count>+1 copies of next byte.
  660.              */
  661.  
  662.             count |= 0xff00;            /* Negate count */
  663.             count = (0 - count) + 1;
  664.             memset(out, *in++, count);        /* Dupe <data> that many times */
  665.             }
  666.         else
  667.             {
  668.  
  669.             /*
  670.              * This is a simple string of bytes to copy.
  671.              */
  672.  
  673.             count++;
  674.             memcpy( out, in, count );
  675.             in += count;
  676.             }
  677.  
  678.         out += count;            /* Advance output past data bytes */
  679.         num_out += count;        /* This many more output bytes done */
  680.         }
  681.  
  682.     return(in);                /* Return advanced pointer */
  683. }
  684.  
  685.  
  686.  
  687.