home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / ARC521-2.ZIP / ARCPACK.C < prev    next >
C/C++ Source or Header  |  1989-12-29  |  8KB  |  276 lines

  1. /*
  2.  * $Header: arcpack.c,v 1.12 88/11/16 17:18:06 hyc Exp $
  3.  */
  4.  
  5. /*  ARC - Archive utility - ARCPACK
  6.  
  7.     Version 3.49, created on 04/21/87 at 11:26:51
  8.  
  9. (C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
  10.  
  11.     By:     Thom Henderson
  12.  
  13.     Description:
  14.      This file contains the routines used to compress a file
  15.      when placing it in an archive.
  16.  
  17.     Language:
  18.      Computer Innovations Optimizing C86
  19. */
  20. #include <stdio.h>
  21. #include "arc.h"
  22. #if    MTS
  23. #include <ctype.h>
  24. #endif
  25.  
  26. void    setcode(), sqinit_cm(), sqputc_cm(), init_cm(), putc_cm();
  27. void    filecopy(), abort(), putc_tst(), init_sq(), scan_sq();
  28. int    getch(), addcrc();
  29.  
  30. /* stuff for non-repeat packing */
  31.  
  32. #define DLE 0x90        /* repeat sequence marker */
  33.  
  34. static unsigned char state;    /* current packing state */
  35.  
  36. /* non-repeat packing states */
  37.  
  38. #define NOHIST  0        /* don't consider previous input */
  39. #define SENTCHAR 1        /* lastchar set, no lookahead yet */
  40. #define SENDNEWC 2        /* run over, send new char next */
  41. #define SENDCNT 3        /* newchar set, send count next */
  42.  
  43. /* packing results */
  44.  
  45. static long     stdlen;        /* length for standard packing */
  46. static short    crcval;        /* CRC check value */
  47.  
  48. void
  49. pack(f, t, hdr)            /* pack file into an archive */
  50.     FILE           *f, *t;    /* source, destination */
  51.     struct heads   *hdr;    /* pointer to header data */
  52. {
  53.     int             c;    /* one character of stream */
  54.     long            ncrlen;    /* length after packing */
  55.     long        huflen;    /* length after squeezing */
  56.     long            lzwlen;    /* length after crunching */
  57.     long        pred_sq(), file_sq();    /* stuff for squeezing */
  58.     long            pred_cm(), sqpred_cm();    /* dynamic crunching cleanup */
  59.     long            tloc, ftell();    /* start of output */
  60.     int        getch();
  61.     int             getc_ncr();
  62.     void            putc_pak();
  63.  
  64.     /* first pass - see which method is best */
  65.  
  66.     tloc = ftell(t);    /* note start of output */
  67.  
  68.     if (!nocomp) {        /* if storage kludge not active */
  69.         if (note) {
  70.             printf(" analyzing, ");
  71.             fflush(stdout);
  72.         }
  73.         state = NOHIST;    /* initialize ncr packing */
  74.         stdlen = ncrlen = 0;    /* reset size counters */
  75.         crcval = 0;    /* initialize CRC check value */
  76.         setcode();    /* initialize encryption */
  77.         init_sq();    /* initialize for squeeze scan */
  78.  
  79.         if (dosquash) {
  80.             sqinit_cm();
  81.             while ((c = getch(f)) != EOF) {    /* for each byte of file */
  82.                 ncrlen++;    /* one more packed byte */
  83.                 scan_sq(c);    /* see what squeezing can do */
  84.                 sqputc_cm(c, t);    /* see what squashing
  85.                              * can do */
  86.             }
  87.             lzwlen = sqpred_cm(t);
  88.         } else {
  89.             init_cm(t);    /* initialize for crunching */
  90.  
  91.             while ((c = getc_ncr(f)) != EOF) {    /* for each byte of file */
  92.                 ncrlen++;    /* one more packed byte */
  93.                 scan_sq(c);    /* see what squeezing can do */
  94.                 putc_cm(c, t);    /* see what crunching can do */
  95.             }
  96.             lzwlen = pred_cm(t);    /* finish up after crunching */
  97.         }
  98.         huflen = pred_sq();    /* finish up after squeezing */
  99.     } else {        /* else kludge the method */
  100.         stdlen = 0;    /* make standard look best */
  101.         ncrlen = huflen = lzwlen = 1;
  102.     }
  103.  
  104.     /* standard set-ups common to all methods */
  105.  
  106.     fseek(f, 0L, 0);    /* rewind input */
  107.     hdr->crc = crcval;    /* note CRC check value */
  108.     hdr->length = stdlen;    /* set actual file length */
  109.     state = NOHIST;        /* reinitialize ncr packing */
  110.     setcode();        /* reinitialize encryption */
  111.  
  112.     /* choose and use the shortest method */
  113.  
  114.     if (kludge && note)
  115.         printf("\n\tS:%ld  P:%ld  S:%ld  C:%ld,\t ",
  116.             stdlen, ncrlen, huflen, lzwlen);
  117.  
  118.     if (stdlen <= ncrlen && stdlen <= huflen && stdlen <= lzwlen) {
  119.         if (note) {
  120.             printf("storing, ");    /* store without compression */
  121.             fflush(stdout);
  122.         }
  123.         hdrver = 2;    /* note packing method */
  124.         fseek(t, tloc, 0);    /* reset output for new method */
  125.         stdlen = crcval = 0;    /* recalc these for kludge */
  126.         while ((c = getch(f)) != EOF)    /* store it straight */
  127.             putc_pak(c, t);
  128.         hdr->crc = crcval;
  129.         hdr->length = hdr->size = stdlen;
  130.     } else if (ncrlen < lzwlen && ncrlen < huflen) {
  131.         if (note) {
  132.             printf("packing, ");    /* pack with repeat */
  133.             fflush(stdout);        /* suppression */
  134.         }
  135.         hdrver = 3;    /* note packing method */
  136.         hdr->size = ncrlen;    /* set data length */
  137.         fseek(t, tloc, 0);    /* reset output for new method */
  138.         while ((c = getc_ncr(f)) != EOF)
  139.             putc_pak(c, t);
  140.     } else if (huflen < lzwlen) {
  141.         if (note) {
  142.             printf("squeezing, ");
  143.             fflush(stdout);
  144.         }
  145.         hdrver = 4;    /* note packing method */
  146.         fseek(t, tloc, 0);    /* reset output for new method */
  147.         hdr->size = file_sq(f, t);    /* note final size */
  148.     } else {
  149.         if (note)
  150.             printf(dosquash ? "squashed, " : "crunched, ");
  151.         hdrver = dosquash ? 9 : 8;
  152.         hdr->size = lzwlen;    /* size should not change */
  153.     }
  154.  
  155.     /* standard cleanups common to all methods */
  156.  
  157.     if (note)
  158.         printf("done. (%ld%%)\n",hdr->length == 0 ?
  159.                 0L : 100L - (100L*hdr->size)/hdr->length);
  160. }
  161.  
  162. /*
  163.  * Non-repeat compression - text is passed through normally, except that a
  164.  * run of more than two is encoded as:
  165.  *
  166.  * <char> <DLE> <count>
  167.  *
  168.  * Special case: a count of zero indicates that the DLE is really a DLE, not a
  169.  * repeat marker.
  170.  */
  171.  
  172. int
  173. getc_ncr(f)            /* get bytes with collapsed runs */
  174.     FILE           *f;    /* file to get from */
  175. {
  176.     static int      lastc;    /* value returned on last call */
  177.     static int      repcnt;    /* repetition counter */
  178.     static int      c;    /* latest value seen */
  179.  
  180.     switch (state) {    /* depends on our state */
  181.     case NOHIST:        /* no relevant history */
  182.         state = SENTCHAR;
  183.         return lastc = getch(f);    /* remember the value next
  184.                          * time */
  185.  
  186.     case SENTCHAR:        /* char was sent. look ahead */
  187.         switch (lastc) {/* action depends on char */
  188.         case DLE:    /* if we sent a real DLE */
  189.             state = NOHIST;    /* then start over again */
  190.             return 0;    /* but note that the DLE was real */
  191.  
  192.         case EOF:    /* EOF is always a special case */
  193.             return EOF;
  194.  
  195.         default:    /* else test for a repeat */
  196.             for (repcnt = 1; (c = getch(f)) == lastc && repcnt < 255; repcnt++);
  197.             /* find end of run */
  198.  
  199.             switch (repcnt) {    /* action depends on run size */
  200.             case 1:/* not a repeat */
  201.                 return lastc = c;    /* but remember value
  202.                              * next time */
  203.  
  204.             case 2:/* a repeat, but too short */
  205.                 state = SENDNEWC;    /* send the second one
  206.                              * next time */
  207.                 return lastc;
  208.  
  209.             default:    /* a run - compress it */
  210.                 state = SENDCNT;    /* send repeat count
  211.                              * next time */
  212.                 return DLE;    /* send repeat marker this
  213.                          * time */
  214.             }
  215.         }
  216.  
  217.     case SENDNEWC:        /* send second char of short run */
  218.         state = SENTCHAR;
  219.         return lastc = c;
  220.  
  221.     case SENDCNT:        /* sent DLE, now send count */
  222.         state = SENDNEWC;
  223.         return repcnt;
  224.  
  225.     default:
  226.         abort("Bug - bad ncr state\n");
  227.     }
  228. }
  229.  
  230. int
  231. getch(f)            /* special get char for packing */
  232.     FILE           *f;    /* file to get from */
  233. {
  234.     int        c;    /* a char from the file */
  235. #if    !DOS
  236.     static int      cr = 0;    /* add \r before \n ? */
  237.  
  238.     if (cr) {
  239.         c = '\n';
  240. #if    MTS
  241.         c = toascii(c);
  242. #endif
  243.         crcval = addcrc(crcval, c);
  244.         stdlen++;
  245.         cr = 0;
  246.         return (c);
  247.     }
  248. #endif
  249.  
  250.     if ((c = fgetc(f)) != EOF) {    /* if not the end of file */
  251. #if    !DOS
  252.         if (!image && (c == '\n')) {
  253.             c = '\r';
  254.             cr = 1;
  255.         }
  256. #endif
  257. #if    MTS
  258.         if (!image)
  259.             c = toascii(c);
  260. #endif
  261.         crcval = addcrc(crcval, c);    /* then update CRC check
  262.                          * value */
  263.         stdlen++;    /* and bump length counter */
  264.     }
  265.     return c;
  266. }
  267.  
  268. void
  269. putc_pak(c, f)            /* put a packed byte into archive */
  270.     char            c;    /* byte to put */
  271.     FILE           *f;    /* archive to put it in */
  272. {
  273.     unsigned char        code();
  274.     putc_tst(code(c), f);    /* put encoded byte, with checks */
  275. }
  276.