home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / tech / pcbsrcs2 / pcbpak2.c < prev    next >
C/C++ Source or Header  |  1991-02-07  |  5KB  |  160 lines

  1. /*
  2. ** general purpose file packer, Copyright (C) Randy Nevin 1989, 1990.
  3. **
  4. ** you may give this software to anyone, make as many copies as you like, and
  5. ** post it on public computer bulletin boards and file servers. you may not
  6. ** sell it or charge any fee for distribution (except for media and postage),
  7. ** remove this comment or the copyright notice from the code, or claim that
  8. ** you wrote this code or anything derived from it. you may modify the code as
  9. ** much as you want (please document clearly with comments, and maintain the
  10. ** coding style), but programs which are derived from this one are subject to
  11. ** the conditions stated here. i am providing this code so that people can
  12. ** learn from it, so if you distribute it, please include source code, not
  13. ** just executables. contact me to report bugs or suggest enhancements; i do
  14. ** not guarantee support, but i will make an effort to help you, and i want to
  15. ** act as a central clearing house for future versions. you should contact me
  16. ** before undertaking a significant development effort, to avoid reinventing
  17. ** the wheel. if you come up with an enhancement you consider particularly
  18. ** useful, i would appreciate being informed so that it can be incorporated in
  19. ** future versions. my address is: Randy Nevin, 1731 211th PL NE, Redmond,
  20. ** WA 98053, USA. this code is available directly from the author; just send a
  21. ** 360k floppy and a self-addressed floppy mailer with sufficient postage.
  22. **
  23. ** HISTORY
  24. ** (name        date        description)
  25. ** ----------------------------------------------------
  26. ** randy nevin        8/6/89        initial version
  27. ** randy nevin        8/15/89        released version 1.00
  28. */
  29.  
  30. /* BUGBUG: doesn't handle files with only one byte value */
  31.  
  32. /*
  33. ** use run-length encoding to compress runs of identical bytes. do this by
  34. ** scanning the input file once, counting the number of times each byte
  35. ** occurs. then pick the one that occurs least frequently (ideally not at all)
  36. ** as the encoding byte. put the encoding type (2) and the encoding byte in
  37. ** the output file. then scan the input file again, writing out the encoded
  38. ** input to the output file. encode by looking for runs of 3 or more identical
  39. ** bytes. for runs, output the encoding byte, the byte count, and the byte
  40. ** value. for non-runs, just output the byte values. be careful if the
  41. ** encoding byte occurs in the input file; a byte count of 0 means just put
  42. ** out one (literal) encoding byte.
  43. */
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48.  
  49. long table[0x100]; /* frequency table */
  50.  
  51. void main( int, char *[] );
  52.  
  53. void main ( argc, argv )
  54.     int argc;
  55.     char *argv[];
  56.     {
  57.     char *self, *t;
  58.     int c, i, enc, val;
  59.     FILE *fin, *fout;
  60.  
  61.     printf( "Copyright (C) Randy Nevin, 1989, 1990. Version 1.00\n" );
  62.     printf( "See source code for rights granted.\n\n" );
  63.     self = argv[0];
  64.     /* get rid of initial part of path */
  65.     if ((t = strrchr( self, '\\' )) || (t = strrchr( self, ':' )))
  66.         self = ++t;
  67.     /* get rid of extension */
  68.     if ((t = strrchr( self, '.' )) && !stricmp( t, ".EXE" ))
  69.         *t = 0;
  70.     if (argc != 3) { /* need infile and outfile */
  71.         fprintf( stderr, "usage: %s infile outfile\n", self );
  72.         exit( -1 );
  73.         }
  74.     if (!(fin = fopen( argv[1], "rb" ))) {
  75.         fprintf( stderr, "can't open %s\n", argv[1] );
  76.         exit( -1 );
  77.         }
  78.     if (!(fout = fopen( argv[2], "wb" ))) {
  79.         fprintf( stderr, "can't open %s\n", argv[2] );
  80.         exit( -1 );
  81.         }
  82.     /* initialize the byte count table */
  83.     for (i = 0; i < 0x100; i++)
  84.         table[i] = 0;
  85.     /* scan the input bytes */
  86.     for (c = getc( fin ); c != EOF; c = getc( fin ))
  87.         table[c] += 1L;
  88.     /* determine the encoding byte */
  89.     for (enc = 0, i = 1; i < 0x100; i++)
  90.         if (table[i] < table[enc])
  91.             enc = i;
  92.     putc( 2, fout ); /* encoding type (2=run-length) */
  93.     putc( (char)enc, fout ); /* identify encoding byte */
  94.     fseek( fin, 0L, SEEK_SET ); /* rewind input file for second pass */
  95.     i = 0; /* use i as byte count */
  96.     while ((c = getc( fin )) != EOF) { /* encode input file */
  97.         if (!i) {
  98.             val = c;
  99.             i = 1;
  100.             }
  101.         else if (c == val)
  102.             i++;
  103.         else { /* flush val */
  104.             if (i >= 3) { /* encode it */
  105.                 putc( (char)enc, fout );
  106.                 putc( (char)i, fout );
  107.                 putc( (char)val, fout );
  108.                 }
  109.             else if (i == 2) { /* do separately */
  110.                 putc( (char)val, fout );
  111.                 if (val == enc) {
  112.                     putc( 0, fout );
  113.                     putc( (char)val, fout );
  114.                     putc( 0, fout );
  115.                     }
  116.                 else
  117.                     putc( (char)val, fout );
  118.                 }
  119.             else if (i == 1) { /* do separately */
  120.                 putc( (char)val, fout );
  121.                 if (val == enc)
  122.                     putc( 0, fout );
  123.                 }
  124.             val = c;
  125.             i = 1;
  126.             }
  127.         if (i == 0xFF) { /* force a flush to avoid count overflow */
  128.             putc( (char)enc, fout );
  129.             putc( (char)i, fout );
  130.             putc( (char)val, fout );
  131.             i = 0;
  132.             }
  133.         } /* end while */
  134.     /* flush val */
  135.     if (i >= 3) { /* encode it */
  136.         putc( (char)enc, fout );
  137.         putc( (char)i, fout );
  138.         putc( (char)val, fout );
  139.         }
  140.     else if (i == 2) { /* do separately */
  141.         putc( (char)val, fout );
  142.         if (val == enc) {
  143.             putc( 0, fout );
  144.             putc( (char)val, fout );
  145.             putc( 0, fout );
  146.             }
  147.         else
  148.             putc( (char)val, fout );
  149.         }
  150.     else if (i == 1) { /* do separately */
  151.         putc( (char)val, fout );
  152.         if (val == enc)
  153.             putc( 0, fout );
  154.         }
  155.     if (ferror( fout ))
  156.         fprintf( stderr, "output error; disk might be full\n" );
  157.     fclose( fout );
  158.     exit( 0 );
  159.     }
  160.