home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 157.lha / Arc_Src / arcpack.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-04-27  |  8.7 KB  |  234 lines

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