home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / OS2ARC_S.ZIP / ARCPACK.C < prev    next >
Text File  |  1987-10-15  |  10KB  |  272 lines

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