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

  1.  
  2.  
  3. /*
  4.  *************************************************************
  5.  * WRITEMAC.C - routines to handle writing of image as a MacPaint
  6.  * file.
  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.  * Write current picture to a disk file. The thing is written with
  43.  * a MacBinary header, and in theory should be in a format that even
  44.  * allows it to be read by a Mac. Our immediate concern, however, is
  45.  * just to get it in a format that this program will recognize if it
  46.  * is ever told to read it again.
  47.  *
  48.  * First we write a preface (the MacBinary and MacPaint headers), and
  49.  * then the data, and then - after we know how many bytes of data we
  50.  * have - we rewrite the preface with the data_fork_size set to the
  51.  * number of bytes in the data.
  52.  */
  53.  
  54. writemac()
  55. {
  56.     int        handle;            /* Of file being written to */
  57.     unsigned    size;            /* # bytes of data */
  58.     static struct _macpaint preface;    /* Our file's preface */
  59.     static BYTE    filename[256];
  60.     
  61.  
  62.     /*
  63.      * Get Mac filename to write with the MacBinary header
  64.      */
  65.      
  66.     mode(TEXT);
  67.     fprintf(stderr, "\nEnter the Macintosh name for this picture. This is NOT");
  68.     fprintf(stderr, "\nthe DOS filename, but is the name that would be used");
  69.     fprintf(stderr, "\nto create the file on the Mac. Up to 63 characters:\n\n");
  70.     gets(filename);
  71.     
  72.     if ( strlen(filename) < 1 )        /* Did he enter a name? */
  73.         {
  74.         strcpy(filename, "JR file");    /* No, give it one */
  75.         }
  76.         
  77.     filename[63] = 0;            /* Truncate in case it's too large */
  78.  
  79.     /*
  80.      * Make our preface presentable
  81.      */
  82.  
  83.     memset( &preface, 0, sizeof( struct _macpaint ) );
  84.     strcpy( preface.macbinary_header.filename, filename );
  85.     preface.macbinary_header.name_size = strlen(filename);
  86.     strcpy( preface.macbinary_header.finder_info.file_type, "PNTGMPNT" );
  87.     preface.macbinary_header.finder_info.flags = 1;
  88.     memcpy( preface.macbinary_header.create_date, "\x9b\x63\xed\x00\x9b\x63\xed\x00", 8 );
  89.     memset( &preface.header.patterns[0][0], 0xff, 38 * 8 );
  90.     preface.header.version = 0x02000000L;
  91.  
  92.     /*
  93.      * Now get DOS filename to write
  94.      */
  95.      
  96.     fprintf(stderr, "\n\nDOS file to write it to:\n\n");
  97.     gets(filename);
  98.     
  99.     if ( strlen(filename) < 1 )        /* Did he enter a name? */
  100.         {
  101.         return;                /* No, skip it */
  102.         }
  103.         
  104.     /*
  105.      * Open the DOS file
  106.      */
  107.      
  108.     handle = open(filename, O_CREAT | O_TRUNC | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD );
  109.     
  110.     if ( (handle != -1) && isatty(handle) )
  111.         {
  112.         close(handle);            /* Don't allow writes to char devices */
  113.         handle = -1;
  114.         }
  115.         
  116.     if ( handle == -1 )
  117.         {
  118.         fprintf(stderr, "\n\nCan't open file '%s'!\nPress RETURN...", filename );
  119.         key();
  120.         return;
  121.         }
  122.         
  123.     /*
  124.      * Write our preface, then true data to file
  125.      */
  126.      
  127.     if ( write( handle, &preface, (sizeof(struct _macpaint) - 1) ) != (sizeof(struct _macpaint) - 1) )
  128.         {
  129. failed:
  130.         close(handle);
  131.         fprintf(stderr, "\n\nError writing to file '%s'!\nPress RETURN...", filename );
  132.         key();
  133.         return;
  134.         }
  135.         
  136.     if ( (size = write_pic(handle)) == 0 )
  137.         {
  138.         goto failed;
  139.         }
  140.  
  141.     size += sizeof(struct _header);            /* Include MacPaint header in size */
  142.         
  143.     /*
  144.      * Rewrite preface with proper data_fork size
  145.      */
  146.      
  147.     if ( lseek( handle, 0L, 0 ) == -1L )
  148.         {
  149.         goto failed;
  150.         }
  151.     
  152.     preface.macbinary_header.data_fork_length = ( ((long) size & 0xff) << 24 ) | ( ((long) size & 0xff00) << 8 );
  153.         
  154.     if ( write( handle, &preface, (sizeof(struct _macpaint) - 1) ) != (sizeof(struct _macpaint) - 1) )
  155.         {
  156.         goto failed;
  157.         }
  158.         
  159.     /*
  160.      * All went well
  161.      */
  162.      
  163.     close(handle);
  164. }
  165.  
  166.  
  167.  
  168. /*
  169.  * Write out entire mem_image to "handle" (which has already been opened
  170.  * for output).
  171.  *
  172.  * We try to compress the image according to the rules for MacPaint
  173.  * repeat compression, by examining the data as it is written and
  174.  * reducing bytes that occur 3 or more times in succession to
  175.  * a 2-byte encoded form.
  176.  *
  177.  * Returns:  0 if error writing to file, else number of actual data bytes
  178.  *           written to the file.
  179.  * 
  180.  */
  181.  
  182. unsigned write_pic(handle)
  183. int handle;                    /* Handle of an already-opened file to write to */
  184. {
  185.     static BYTE    repeat_buf[ (MAC_HORIZ/8) + 1 ];
  186.     static BYTE    outbuf[ (MAC_HORIZ/8) * 2 ];
  187.  
  188.     BYTE *        p;
  189.  
  190.     int        outsize,        /* # output bytes to write to file */
  191.             repeat_count,        /* # repetitions of a repeated byte */
  192.             repeat_index,        /* Offset into repeat_buf */
  193.             next_repeat,        /* The next repeat count after ours */
  194.             line;            /* What line of image we're doing */
  195.             
  196.  
  197.     unsigned    total_out;        /* Total number of bytes written to file */
  198.             
  199.     /*
  200.      * Examine, encode, and write out each line as a separate entity
  201.      */
  202.  
  203.     p = &mem_image[0][0];            /* Start at at front of image */
  204.     total_out = 0;                /* No bytes written yet */
  205.     
  206.     for ( line = 0; line < MAC_VERT; line++ )
  207.         {
  208.  
  209.         /*
  210.          * Examine this line, and get array of repeat counts into
  211.          * repeat_buf
  212.          */
  213.          
  214.         outscan(p, repeat_buf);
  215.         
  216.         /*
  217.          * Decode repeat counts, using analysis thereof to determine
  218.          * which bytes get written as simple images and which ones
  219.          * get written as encoded repeat patterns.
  220.          */
  221.          
  222.         outsize = 0;            /* At front of output buffer */
  223.         repeat_index = 0;        /* At front of repeat list too */
  224.         
  225.         while( repeat_count = repeat_buf[repeat_index++] )
  226.             {
  227.             if ( repeat_count < 3 )
  228.                 {
  229.  
  230.                 /*
  231.                  * This is a straight copy, 'cause this byte
  232.                  * doesn't occur enough times in a row to
  233.                  * warrant an encoded form. Since we're
  234.                  * copying verbatim anyway, we may as well
  235.                  * include anybody immediately following us
  236.                  * who is likewise just a straight copy (i.e. -
  237.                  * whose repeat count is less than 3).
  238.                  */
  239.                  
  240.                 while( next_repeat = repeat_buf[ repeat_index ] )
  241.                     {
  242.                     
  243.                     /*
  244.                      * If this next repeat count is >= 3,
  245.                      * then he deserves encoding. So don't
  246.                      * swallow him into this straight-copy mess.
  247.                      */
  248.                      
  249.                     if ( next_repeat >= 3 )
  250.                         {
  251.                         break;
  252.                         }
  253.                         
  254.                     /*
  255.                      * Otherwise just add his paltry repeat count
  256.                      * to however many bytes we're already
  257.                      * gonna copy directly.
  258.                      */
  259.                      
  260.                     repeat_count += next_repeat;
  261.                     repeat_index++;
  262.                     }
  263.                     
  264.                 /*
  265.                  * We now know how many total bytes deserve to
  266.                  * be copied directly. Do it.
  267.                  */
  268.                  
  269.                 outbuf[ outsize++ ] = repeat_count - 1;        /* Use positive repeat count */
  270.                 memcpy( &outbuf[outsize], p, repeat_count );
  271.  
  272.                 /*
  273.                  * Advance everybody over the bytes that we
  274.                  * just copied.
  275.                  */
  276.  
  277.                 p += repeat_count;
  278.                 outsize += repeat_count;
  279.                 }
  280.             else
  281.                 {
  282.                 
  283.                 /*
  284.                  * This repeat count is 3 or more. It is
  285.                  * worth encoding into a 2-byte repeat sequence.
  286.                  */
  287.                  
  288.                 outbuf[ outsize++ ] = 0 - (repeat_count - 1);    /* Use negative repeat count */
  289.                 outbuf[ outsize++ ] = *p;
  290.                 
  291.                 /*
  292.                  * Skip over all repeated bytes in input
  293.                  */
  294.                  
  295.                 p += repeat_count;
  296.                 }
  297.             }
  298.             
  299.         /*
  300.          * We're done with this line. Write it to the file.
  301.          */
  302.          
  303.         if ( write(handle, outbuf, outsize) != outsize )
  304.             {
  305.             return(0);        /* Error writing file */
  306.             }
  307.             
  308.         total_out += outsize;        /* Bump total written */
  309.         }
  310.  
  311.     /*
  312.      * Fill out the last 512-byte Mac sector, for no reason other than that
  313.      * the files that we've seen seem to have this done.
  314.      */
  315.      
  316.     outsize = sizeof(outbuf);
  317.     memset( outbuf, 0, outsize );
  318.     repeat_count = 512 - (total_out & 511);    /* Re-use a stray variable! */
  319.     
  320.     while( repeat_count )
  321.         {
  322.         if ( repeat_count < outsize )    /* Almost done? */
  323.             {
  324.             outsize = repeat_count;    /* Yes, fine-tune it */
  325.             }
  326.             
  327.         repeat_count -= outsize;    /* Update stats first */
  328.         total_out += outsize;
  329.         
  330.         if ( write(handle, outbuf, outsize) != outsize )
  331.             {
  332.             return(0);        /* Bad write */
  333.             }
  334.             
  335.         }
  336.  
  337.     return(total_out);            /* No errors */
  338. }
  339.  
  340.  
  341.  
  342. /*
  343.  * Examine 72-byte MacPaint line at "in", and from it build (at "out")
  344.  * a list of the repeated-byte string lengths contained in it. Each
  345.  * byte of "out" holds a count of the number of identical bytes that
  346.  * were found. The "out" array is terminated with a NUL byte.
  347.  *
  348.  * Example:  in = "TESST"
  349.  *          out = 1,1,2,1,NUL
  350.  *
  351.  * Worst case (from a compression standpoint) will result in "out" holding
  352.  * 72 bytes (each of which has the binary value 1), plus the terminating
  353.  * NUL:
  354.  *
  355.  *    1,1,1,1,1,1,1,...1,1,1,1,1,NUL
  356.  *
  357.  * Best case yields "out" of one byte (plus the NUL):
  358.  *
  359.  *    72,NUL
  360.  *
  361.  * This is all part of our desire to compress the output as much as
  362.  * possible. It may or may not make sense on a Mac. But it does produce
  363.  * output that is acceptable to this program when it's read back in.
  364.  *
  365.  */
  366.  
  367. outscan(in, out)
  368. BYTE *in;                    /* Raw MacPaint line */
  369. BYTE *out;                    /* Where to put repeat list */
  370. {
  371.     register int    i,            /* Scratch */
  372.             count;            /* Repeat count for current string */
  373.             
  374.     int        byte;            /* What byte number we're doing (0-71) */
  375.     BYTE        val;            /* Value of current byte */
  376.     
  377.     /*
  378.      * Scan through all 72 bytes of this line
  379.      */
  380.      
  381.     byte = 0;                /* Start at the front */
  382.     
  383.     while ( byte < (MAC_HORIZ/8) )
  384.         {
  385.         i = byte + 1;            /* First potential repeat */
  386.         count = 1;            /* We're at least 1 long already! */
  387.         val = in[byte];            /* What to compare next bytes to */
  388.         
  389.         /*
  390.          * See how many subsequent bytes are the same as this one
  391.          */
  392.          
  393.         while( (i < (MAC_HORIZ/8)) && ( in[i++] == val ) )
  394.             {
  395.             count++;        /* Got another hit! */
  396.             }
  397.             
  398.         /*
  399.          * Store this repeat count into "out", and advance over that
  400.          * many input bytes.
  401.          */
  402.          
  403.         *out++ = count;
  404.         byte += count;
  405.         }
  406.         
  407.     *out = 0;                /* NUL-terminate "out" */
  408. }
  409.  
  410.         
  411.     
  412.     
  413.