home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / cpm68k / arc68k.arc / ARCPACK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-11-27  |  9.3 KB  |  224 lines

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