home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / unix / unsit.shr < prev    next >
Text File  |  1989-05-15  |  25KB  |  1,010 lines

  1.  
  2. # This is a shell archive.  Remove anything before this line,
  3. # then unpack it by saving it in a file and typing "sh file".
  4. #
  5. # Wrapped by rascal!werner on Thu Nov  3 19:33:40 CST 1988
  6. # Contents:  unsit.1 unsit.c unsit.h
  7.  
  8. echo x - unsit.1
  9. sed 's/^@//' > "unsit.1" <<'@//E*O*F unsit.1//'
  10. @.TH UNSIT L "January 15, 1988"
  11. @.UC
  12. @.SH NAME
  13. unsit \- extract/list files in a Macintosh Stuffit archive file
  14. @.SH SYNOPSIS
  15. @.B unsit
  16. [
  17. @.B \-dlqruv
  18. ] file
  19. @.br
  20. @.SH DESCRIPTION
  21. For the Stuffit archive file listed, 
  22. @.I unsit
  23. extracts the files in archive into separate files.
  24. This makes it possible, for example, to separate a large StuffIt file
  25. into component files for selective downloading, rather than
  26. downloading the larger archive file just to extract a single, small
  27. file.  It also allows the use of StuffIt to compress a group of files
  28. into a single, smaller archive that can be uploaded to a Unix system
  29. for storage, printing, etc.
  30. @.PP
  31. In the normal mode, both the data and the resource forks of the
  32. component Macintosh files in the archive are extracted and stored in
  33. Unix files with the extension
  34. @.I .data
  35. and 
  36. @.I .rsrc
  37. appended to the end of the Macintosh file name.
  38. In addition, a 
  39. @.I .info
  40. file will be created with the Finder information.
  41. These three file are compatible with the
  42. @.I macput
  43. program for downloading to a Mac running Macterminal.
  44. If only the data or resource fork is extracted, no addition extension is
  45. appended to the Mac file name.
  46. Characters in the Mac file name that are illegal (or unwieldy, like spaces)
  47. are changed to underscores in the Unix file name.  The true Mac file name 
  48. is retained in the
  49. @.I .info
  50. file and is restored when the file is downloaded.
  51. @.PP
  52. The options are similar to those for 
  53. @.I macput
  54. and
  55. @.I unpit.
  56. @.TP
  57. @.B \-l
  58. List the files in the archive but do not extract them.  The name, size,
  59. type, and creator of each file is listed.
  60. @.TP
  61. @.B \-r
  62. Extract resources forks only.
  63. @.TP
  64. @.B \-d
  65. Extract data forks only.
  66. @.TP
  67. @.B \-u
  68. Extract data fork and change into a Unix text file.
  69. This only works if the file is really a text file.
  70. @.TP
  71. @.B \-q
  72. Query user before extracting files.
  73. @.TP
  74. @.B \-v
  75. Verbose option.  Causes 
  76. @.I unsit
  77. to list name, size, type, and creator of each file extracted.
  78. @.SH BUGS
  79. Files that were compressed by StuffIt with the Lempel-Ziv method and are
  80. extracted with the 
  81. @.B \-u
  82. switch (text files) are not checked for a correct CRC value when 
  83. @.I unsit
  84. uncompresses them.  This is because 
  85. @.I unsit
  86. pipes the data through
  87. @.I compress
  88. and
  89. @.I tr
  90. to extract the file and never has a chance to do the CRC check.
  91. @.PP
  92. The
  93. @.I compress
  94. program has been observed to go into strange states when uncompressing a 
  95. damaged file.  Often it will get stuck writing out bogus data until the
  96. disk fills up.  Since 
  97. @.I unsit
  98. sends data through 
  99. @.I compress,
  100. the same problem could occur when extracting files from a damaged Stuffit
  101. archive.
  102. @.SH FILES
  103. For archives that have been compressed with the Lempel-Ziv method, the 
  104. @.I compress 
  105. program must be present on the system and in the search path since 
  106. @.I unsit 
  107. uses it for the uncompressing.
  108. @.I Compress
  109. is available from the comp.sources.unix archives.
  110. @.SH AUTHOR
  111. Allan G. Weber (weber%brand.usc.edu@oberon.usc.edu)
  112. @//E*O*F unsit.1//
  113. chmod u=rw,g=r,o=r unsit.1
  114.  
  115. echo x - unsit.c
  116. sed 's/^@//' > "unsit.c" <<'@//E*O*F unsit.c//'
  117. /*
  118.         unsit - Macintosh StuffIt file extractor
  119.  
  120.             Version 1, for StuffIt 1.31
  121.  
  122. This program will unpack a Macintosh StuffIt file into separate files.
  123. The data fork of a StuffIt file contains both the data and resource
  124. forks of the packed files.  The program will unpack each Mac file into
  125. separate .data, .rsrc., and .info files that can be downloaded to a
  126. Mac using macput.  The program is much like the "unpit" program for
  127. breaking apart Packit archive files.
  128.  
  129.             ***** IMPORTANT *****
  130. To extract StuffIt files that have been compressed with the Lempel-Ziv
  131. compression method, unsit pipes the data through the "compress"
  132. program with the appropriate switches, rather than incorporate the
  133. uncompression routines within "unsit".  Therefore, it is necessary to
  134. have the "compress" program on the system and in the search path to
  135. make "unsit" work.  "Compress" is available from the comp.sources.unix
  136. archives.
  137.  
  138. The program syntax is much like unpit and macput/macget, with some added
  139. options:
  140.  
  141.     unsit [-rdulvq] stuffit-file.data
  142.  
  143. The -r and -d flags will cause only the resource and data forks to be
  144. written.  The -u flag will cause only the data fork to be written and
  145. to have carriage return characters changed to Unix newline characters.
  146. The -l flag will make the program only list the files in the StuffIt
  147. file.  The -v flag causes the program to list the names, sizes, type,
  148. and creators of the files it is writing.  The -q flag causes it to
  149. list the name, type and size of each file and wait for a 'y' or 'n'
  150. for either writing that file or skipping it, respectively.
  151.  
  152. Some of the program is borrowed from the macput.c/macget.c programs.
  153. Many, many thanks to Raymond Lau, the author of StuffIt, for including 
  154. information on the format of the StuffIt archives in the documentation.
  155.  
  156.     Author: Allan G. Weber
  157.         weber%brand.usc.edu@oberon.usc.edu
  158.         ...sdcrdcf!usc-oberon!brand!weber
  159.     Date:   January 15, 1988
  160.  
  161. */
  162.  
  163. #include <stdio.h>
  164.  
  165. typedef long OSType;
  166.  
  167. #include "unsit.h"
  168.  
  169. /*
  170.   The following defines the name of the compress program that is used 
  171.   for the uncompression of Lempel-Ziv compressed files.  If the path is
  172.   set up to include the right directory, this should work.
  173. */
  174. #define COMPRESS   "compress"
  175.  
  176. #define IOBUFSIZ   4096
  177.  
  178. #define INIT_CRC 0L
  179. extern unsigned short updcrc();
  180.  
  181. #define INFOBYTES 128
  182.  
  183. #define BYTEMASK 0xff
  184.  
  185. #define S_SIGNATURE    0
  186. #define S_NUMFILES     4
  187. #define S_ARCLENGTH    6
  188. #define S_SIGNATURE2  10
  189. #define    S_VERSION     14
  190. #define SITHDRSIZE    22
  191.  
  192. #define F_COMPRMETHOD    0
  193. #define F_COMPDMETHOD    1
  194. #define F_FNAME          2
  195. #define F_FTYPE         66
  196. #define F_CREATOR       70
  197. #define F_FNDRFLAGS     74
  198. #define F_CREATIONDATE  76
  199. #define F_MODDATE       80
  200. #define F_RSRCLENGTH    84
  201. #define F_DATALENGTH    88
  202. #define F_COMPRLENGTH   92
  203. #define F_COMPDLENGTH   96
  204. #define F_RSRCCRC      100
  205. #define F_DATACRC      102
  206. #define F_HDRCRC       110
  207. #define FILEHDRSIZE    112
  208.  
  209. #define F_NAMELEN 63
  210. #define I_NAMELEN 69    /* 63 + strlen(".info") + 1 */
  211.  
  212. /* The following are copied out of macput.c/macget.c */
  213. #define I_NAMEOFF 1
  214. /* 65 <-> 80 is the FInfo structure */
  215. #define I_TYPEOFF 65
  216. #define I_AUTHOFF 69
  217. #define I_FLAGOFF 73
  218. #define I_LOCKOFF 81
  219. #define I_DLENOFF 83
  220. #define I_RLENOFF 87
  221. #define I_CTIMOFF 91
  222. #define I_MTIMOFF 95
  223.  
  224. #define INITED_BUG
  225. #define INITED_OFF    I_FLAGOFF    /* offset to byte with Inited flag */
  226. #define INITED_MASK    (~1)        /* mask to '&' with byte to reset it */
  227.  
  228. #define TEXT 0
  229. #define DATA 1
  230. #define RSRC 2
  231. #define FULL 3
  232. #define DUMP 4
  233.  
  234. #define NODECODE 0
  235. #define DECODE   1
  236.  
  237. struct node {
  238.     int flag, byte;
  239.     struct node *one, *zero;
  240. } nodelist[512], *nodeptr, *read_tree();    /* 512 should be big enough */
  241.  
  242. char f_info[I_NAMELEN];
  243. char f_data[I_NAMELEN];
  244. char f_rsrc[I_NAMELEN];
  245.  
  246. char info[INFOBYTES];
  247. char text[F_NAMELEN+1];
  248. char iobuf[IOBUFSIZ];
  249.  
  250. int mode, txtmode, listonly, verbose, query;
  251. int bit, chkcrc;
  252. FILE *infp;
  253.  
  254. long get4();
  255. short get2();
  256. unsigned short write_file();
  257.  
  258. main(argc, argv)
  259. int argc;
  260. char *argv[];
  261. {
  262.     unsigned short crc;
  263.     int i, n;
  264.     char c;
  265.     struct sitHdr sithdr;
  266.     struct fileHdr filehdr;
  267.     extern int optind;
  268.     extern char *optarg;
  269.     int errflg;
  270.  
  271.     mode = FULL;
  272.     errflg = 0;
  273.  
  274.     while ((c = getopt(argc, argv, "dlqruvx")) != (char)EOF)
  275.             /* added (char) for native amdahl compiler bug NRT*/
  276.     switch (c) {
  277.       case 'r':
  278.         mode = RSRC;
  279.         break;
  280.       case 'd':
  281.         mode = DATA;
  282.         break;
  283.       case 'u':
  284.         mode = TEXT;
  285.         break;
  286.       case 'l':
  287.         listonly++;
  288.         break;
  289.       case 'q':
  290.         query++;
  291.         break;
  292.       case 'v':
  293.         verbose++;
  294.         break;
  295.       case 'x':
  296.         mode = DUMP;
  297.         break;
  298.       case '?':
  299.         errflg++;
  300.         break;
  301.     }
  302.     if (errflg) {
  303.     usage();
  304.     exit(1);
  305.     }
  306.  
  307.     if (optind == argc) {
  308.     usage();
  309.     exit(1);
  310.     }
  311.     else {
  312.     if ((infp = fopen(argv[optind], "r")) == NULL) {
  313.         fprintf(stderr,"Can't open input file \"%s\"\n",argv[optind]);
  314.         exit(1);
  315.     }
  316.     }
  317.  
  318.     if (readsithdr(&sithdr) == 0) {
  319.     fprintf(stderr, "Can't read file header\n");
  320.     exit(1);
  321.     }
  322.     /* 
  323.       printf("numfiles=%d, arclength=%ld\n", sithdr.numFiles, sithdr.arcLength);
  324.       */
  325.     
  326.     for (i = 0; i < sithdr.numFiles; i++) {
  327.     if (readfilehdr(&filehdr) == -1) {
  328.         fprintf(stderr, "Can't read file header #%d\n", i+1);
  329.         exit(1);
  330.     }
  331.  
  332.     /*
  333.       printf("rsrclen=%ld, datalen=%ld, rsrccrc=%d, datacrc=%d\n",
  334.       filehdr.compRLength, filehdr.compDLength,
  335.       filehdr.rsrcCRC, filehdr.dataCRC);
  336.       */
  337.     if (f_rsrc[0] != '\0') {
  338.         txtmode = 0;
  339.         crc = write_file(f_rsrc, filehdr.compRLength,
  340.                  filehdr.rsrcLength, filehdr.compRMethod);
  341.         if (chkcrc && filehdr.rsrcCRC != crc) {
  342.         fprintf(stderr,
  343.             "CRC error on resource fork: need 0x%04x, got 0x%04x\n",
  344.             filehdr.rsrcCRC, crc);
  345.         break;
  346.         }
  347.     }
  348.     else {
  349.         fseek(infp, filehdr.compRLength, 1);
  350.     }
  351.     if (f_data[0] != '\0') {
  352.         txtmode = (mode == TEXT);
  353.         crc = write_file(f_data, filehdr.compDLength,
  354.                  filehdr.dataLength, filehdr.compDMethod);
  355.         if (chkcrc && filehdr.dataCRC != crc) {
  356.         fprintf(stderr,
  357.             "CRC error on data fork: need 0x%04x, got 0x%04x\n",
  358.             filehdr.dataCRC, crc);
  359.         break;
  360.         }
  361.     }
  362.     else {
  363.         fseek(infp, filehdr.compDLength, 1);
  364.     }
  365.     }
  366. }
  367.  
  368. usage()
  369. {
  370.     fprintf(stderr, "Usage: unsit [-rdulvq] filename\n");
  371. }
  372.  
  373. readsithdr(s)
  374. struct sitHdr *s;
  375. {
  376.     char temp[SITHDRSIZE];
  377.  
  378.     if (fread(temp, 1, SITHDRSIZE, infp) != SITHDRSIZE) {
  379.     fprintf(stderr, "Can't read file header\n");
  380.     return(0);
  381.     }
  382.     
  383.     if (strncmp(temp + S_SIGNATURE,  "SIT!", 4) != 0 ||
  384.     strncmp(temp + S_SIGNATURE2, "rLau", 4) != 0) {
  385.     fprintf(stderr, "Not a StuffIt file\n");
  386.     return(0);
  387.     }
  388.  
  389.     s->numFiles = get2(temp + S_NUMFILES);
  390.     s->arcLength = get4(temp + S_ARCLENGTH);
  391.  
  392.     return(1);
  393. }
  394.  
  395. readfilehdr(f)
  396. struct fileHdr *f;
  397. {
  398.     register int i;
  399.     unsigned short crc;
  400.     int n, j, write_it;
  401.     char hdr[FILEHDRSIZE];
  402.     char *tp, temp[10];
  403.     FILE *fp;
  404.  
  405.     for (i = 0; i < INFOBYTES; i++)
  406.     info[i] = '\0';
  407.  
  408.     if (fread(hdr, 1, FILEHDRSIZE, infp) != FILEHDRSIZE) {
  409.     fprintf(stderr, "Can't read file header\n");
  410.     return(-1);
  411.     }
  412.     crc = INIT_CRC;
  413.     crc = updcrc(crc, hdr, FILEHDRSIZE - 2);
  414.  
  415.     f->hdrCRC = get2(hdr + F_HDRCRC);
  416.     if (f->hdrCRC != crc) {
  417.     fprintf(stderr, "Header CRC mismatch: got 0x%04x, need 0x%04x\n",
  418.         f->hdrCRC, crc);
  419.     return(-1);
  420.     }
  421.  
  422.     n = hdr[F_FNAME] & BYTEMASK;
  423.     if (n > F_NAMELEN)
  424.     n = F_NAMELEN;
  425.     info[I_NAMEOFF] = n;
  426.     copy(info + I_NAMEOFF + 1, hdr + F_FNAME + 1, n);
  427.     strncpy(text, hdr + F_FNAME + 1, n);
  428.     text[n] = '\0';
  429.  
  430.     f->compRMethod = hdr[F_COMPRMETHOD];
  431.     f->compDMethod = hdr[F_COMPDMETHOD];
  432.     f->rsrcLength = get4(hdr + F_RSRCLENGTH);
  433.     f->dataLength = get4(hdr + F_DATALENGTH);
  434.     f->compRLength = get4(hdr + F_COMPRLENGTH);
  435.     f->compDLength = get4(hdr + F_COMPDLENGTH);
  436.     f->rsrcCRC = get2(hdr + F_RSRCCRC);
  437.     f->dataCRC = get2(hdr + F_DATACRC);
  438.  
  439.     write_it = 1;
  440.     if (listonly || verbose || query) {
  441.     printf("name=\"%s\", type=%4.4s, author=%4.4s, data=%ld, rsrc=%ld",
  442.            text, hdr + F_FTYPE, hdr + F_CREATOR,
  443.            f->dataLength, f->rsrcLength);
  444.     if (listonly) {
  445.         write_it = 0;
  446.         putchar('\n');
  447.     }
  448.     else if (query) {
  449.         printf(" ? ");
  450.         fgets(temp, sizeof(temp) - 1, stdin);
  451.         tp = temp;
  452.         write_it = 0;
  453.         while (*tp != '\0') {
  454.         if (*tp == 'y' || *tp == 'Y') {
  455.             write_it = 1;
  456.             break;
  457.         }
  458.         else
  459.             tp++;
  460.         }
  461.     }
  462.     else
  463.         putchar('\n');
  464.     }
  465.  
  466.     /* check for illegal Unix characters in file name */
  467.     for (tp = text; *tp; tp++)
  468.     if (*tp <= ' ' || *tp == '/' || *tp > '~')
  469.         *tp = '_';
  470.  
  471.     f_data[0] = f_rsrc[0] = '\0';
  472.  
  473.     if (write_it) {
  474.     switch (mode) {
  475.       case FULL:
  476.         sprintf(f_data, "%s.data", text);    /* can be d.%s if name too long NRT*/
  477.         sprintf(f_rsrc, "%s.rsrc", text);    /* can be r.%s if name too long NRT*/
  478.  
  479.         copy(info + I_TYPEOFF, hdr + F_FTYPE, 4);
  480.         copy(info + I_AUTHOFF, hdr + F_CREATOR, 4);
  481.         copy(info + I_FLAGOFF, hdr + F_FNDRFLAGS, 2);
  482. #ifdef INITED_BUG
  483.         info[INITED_OFF] &= INITED_MASK; /* reset init bit */
  484. #endif
  485.         copy(info + I_DLENOFF, hdr + F_DATALENGTH, 4);
  486.         copy(info + I_RLENOFF, hdr + F_RSRCLENGTH, 4);
  487.         copy(info + I_CTIMOFF, hdr + F_CREATIONDATE, 4);
  488.         copy(info + I_MTIMOFF, hdr + F_MODDATE, 4);
  489.  
  490.         sprintf(f_info, "%s.info", text);    /* can be i.%s if name too long NRT*/
  491.         fp = fopen(f_info, "w");
  492.         if (fp == NULL) {
  493.         perror(f_info);
  494.         exit(1);
  495.         }
  496.         fwrite(info, 1, INFOBYTES, fp);
  497.         fclose(fp);
  498.         break;
  499.       case RSRC:
  500.         sprintf(f_rsrc, "%s.rsrc", text);
  501.         break;
  502.       case DATA:
  503.       case TEXT:
  504.         sprintf(f_data, "%s", text);
  505.         break;
  506.       case DUMP:
  507.         sprintf(f_data, "%s.ddump", text);
  508.         sprintf(f_rsrc, "%s.rdump", text);
  509.         f->compRMethod = f->compDMethod = noComp;
  510.         break;
  511.     }
  512.     }
  513.     return(1);
  514. }
  515.  
  516. unsigned short write_file(fname, ibytes, obytes, type)
  517. char *fname;
  518. long ibytes, obytes;
  519. int type;
  520. {
  521.     unsigned short crc;
  522.     int i, n, ch, lastch;
  523.     FILE *outf;
  524.     char temp[256];
  525.  
  526.     crc = INIT_CRC;
  527.     chkcrc = 1;            /* usually can check the CRC */
  528.  
  529.     switch (type) {
  530.       case noComp:        /* no compression */
  531.     outf = fopen(fname, "w");
  532.     if (outf == NULL) {
  533.         perror(fname);
  534.         exit(1);
  535.     }
  536.     while (ibytes > 0) {
  537.         n = (ibytes > IOBUFSIZ) ? IOBUFSIZ : ibytes;
  538.         n = fread(iobuf, 1, n, infp);
  539.         if (n == 0)
  540.         break;
  541.         crc = updcrc(crc, iobuf, n);
  542.         outc(iobuf, n, outf);
  543.         ibytes -= n;
  544.     }
  545.     fclose(outf);
  546.     break;
  547.       case repComp:        /* run length encoding */
  548.     outf = fopen(fname, "w");
  549.     if (outf == NULL) {
  550.         perror(fname);
  551.         exit(1);
  552.     }
  553.     while (ibytes > 0) {
  554.         ch = getc(infp) & 0xff;
  555.         ibytes--;
  556.         if (ch == 0x90) {
  557.         n = (getc(infp) & 0xff) - 1;
  558.         ibytes--;
  559.         for (i = 0; i < n; i++)
  560.             iobuf[i] = lastch;
  561.         crc = updcrc(crc, iobuf, n);
  562.         outc(iobuf, n, outf);
  563.         }
  564.         else {
  565.         iobuf[0] = ch;
  566.         crc = updcrc(crc, iobuf, 1);
  567.         lastch = ch;
  568.         outc(iobuf, 1, outf);
  569.         }
  570.     }
  571.     fclose(outf);
  572.     break;
  573.       case lpzComp:        /* LZW compression */
  574.     sprintf(temp, "%s%s", COMPRESS, " -d -c -n -b 14 ");
  575.     if (txtmode) {
  576.         strcat(temp, "| tr \'\\015\' \'\\012\' ");
  577.         chkcrc = 0;        /* can't check CRC in this case */
  578.     }
  579.     strcat(temp, "> ");
  580.     strcat(temp, fname);
  581.     outf = popen(temp, "w");
  582.     if (outf == NULL) {
  583.         perror(fname);
  584.         exit(1);
  585.     }
  586.     while (ibytes > 0) {
  587.         n = (ibytes > IOBUFSIZ) ? IOBUFSIZ : ibytes;
  588.         n = fread(iobuf, 1, n, infp);
  589.         if (n == 0)
  590.         break;
  591.         fwrite(iobuf, 1, n, outf);
  592.         ibytes -= n;
  593.     }
  594.     pclose(outf);
  595.     if (chkcrc) {
  596.         outf = fopen(fname, "r"); /* read the file to get CRC value */
  597.         if (outf == NULL) {
  598.         perror(fname);
  599.         exit(1);
  600.         }
  601.         while (1) {
  602.         n = fread(iobuf, 1, IOBUFSIZ, outf);
  603.         if (n == 0)
  604.             break;
  605.         crc = updcrc(crc, iobuf, n);
  606.         }
  607.         fclose(outf);
  608.     }
  609.     break;
  610.       case hufComp:        /* Huffman compression */
  611.     outf = fopen(fname, "w");
  612.     if (outf == NULL) {
  613.         perror(fname);
  614.         exit(1);
  615.     }
  616.     nodeptr = nodelist;
  617.     bit = 0;        /* put us on a byte boundary */
  618.     read_tree();
  619.     while (obytes > 0) {
  620.         n = (obytes > IOBUFSIZ) ? IOBUFSIZ : obytes;
  621.         for (i = 0; i < n; i++)
  622.         iobuf[i] = gethuffbyte(DECODE);
  623.         crc = updcrc(crc, iobuf, n);
  624.         outc(iobuf, n, outf);
  625.         obytes -= n;
  626.     }
  627.     fclose(outf);
  628.     break;
  629.       default:
  630.     fprintf(stderr, "Unknown compression method\n");
  631.     return(-1);
  632.     }
  633.  
  634.     return(crc & 0xffff);
  635. }
  636.  
  637. outc(p, n, fp)
  638. char *p;
  639. int n;
  640. FILE *fp;
  641. {
  642.     register char *p1;
  643.     register int i;
  644.     if (txtmode) {
  645.     for (i = 0, p1 = p; i < n; i++, p1++)
  646.         if ((*p1 & BYTEMASK) == '\r')
  647.         *p1 = '\n';
  648.     }
  649.     fwrite(p, 1, n, fp);
  650. }
  651.  
  652. long get4(bp)
  653. char *bp;
  654. {
  655.     register int i;
  656.     long value = 0;
  657.  
  658.     for (i = 0; i < 4; i++) {
  659.     value <<= 8;
  660.     value |= (*bp & BYTEMASK);
  661.     bp++;
  662.     }
  663.     return(value);
  664. }
  665.  
  666. short get2(bp)
  667. char *bp;
  668. {
  669.     register int i;
  670.     int value = 0;
  671.  
  672.     for (i = 0; i < 2; i++) {
  673.     value <<= 8;
  674.     value |= (*bp & BYTEMASK);
  675.     bp++;
  676.     }
  677.     return(value);
  678. }
  679.  
  680. copy(p1, p2, n)
  681. char *p1, *p2;
  682. int n;
  683. {
  684.     while (n-- > 0)
  685.         *p1++ = *p2++;
  686. }
  687.  
  688. /* This routine recursively reads the Huffman encoding table and builds
  689.    and decoding tree. */
  690.  
  691. struct node *read_tree()
  692. {
  693.     struct node *np;
  694.     np = nodeptr++;
  695.     if (getbit() == 1) {
  696.         np->flag = 1;
  697.         np->byte = gethuffbyte(NODECODE);
  698.     }
  699.     else {
  700.         np->flag = 0;
  701.         np->zero = read_tree();
  702.         np->one  = read_tree();
  703.     }
  704.     return(np);
  705. }
  706.  
  707. /* This routine returns the next bit in the input stream (MSB first) */
  708.  
  709. getbit()
  710. {
  711.     static char b;
  712.     if (bit == 0) {
  713.         b = getc(infp) & 0xff;
  714.         bit = 8;
  715.     }
  716.     bit--;
  717.     return((b >> bit) & 1);
  718. }
  719.  
  720. /* This routine returns the next 8 bits.  If decoding is on, it finds the
  721. byte in the decoding tree based on the bits from the input stream.  If
  722. decoding is not on, it either gets it directly from the input stream or
  723. puts it together from 8 calls to getbit(), depending on whether or not we
  724. are currently on a byte boundary
  725. */
  726. gethuffbyte(decode)
  727. int decode;
  728. {
  729.     register struct node *np;
  730.     register int i, b;
  731.     if (decode == DECODE) {
  732.         np = nodelist;
  733.         while (np->flag == 0)
  734.             np = (getbit()) ? np->one : np->zero;
  735.         b = np->byte;
  736.     }
  737.     else {
  738.         if (bit == 0)    /* on byte boundary? */
  739.             b = getc(infp) & 0xff;
  740.         else {        /* no, put a byte together */
  741.             b = 0;
  742.             for (i = 8; i > 0; i--) {
  743.                 b = (b << 1) + getbit();
  744.             }
  745.         }
  746.     }
  747.     return(b);
  748. }
  749.  
  750. /* updcrc(3), crc(1) - calculate crc polynomials
  751.  *
  752.  * Calculate, intelligently, the CRC of a dataset incrementally given a 
  753.  * buffer full at a time.
  754.  * 
  755.  * Usage:
  756.  *     newcrc = updcrc( oldcrc, bufadr, buflen )
  757.  *         unsigned int oldcrc, buflen;
  758.  *         char *bufadr;
  759.  *
  760.  * Compiling with -DTEST creates a program to print the CRC of stdin to stdout.
  761.  * Compile with -DMAKETAB to print values for crctab to stdout.  If you change
  762.  *    the CRC polynomial parameters, be sure to do this and change
  763.  *    crctab's initial value.
  764.  *
  765.  * Notes:
  766.  *  Regards the data stream as an integer whose MSB is the MSB of the first
  767.  *  byte recieved.  This number is 'divided' (using xor instead of subtraction)
  768.  *  by the crc-polynomial P.
  769.  *  XMODEM does things a little differently, essentially treating the LSB of
  770.  * the first data byte as the MSB of the integer. Define SWAPPED to make
  771.  * things behave in this manner.
  772.  *
  773.  * Author:    Mark G. Mendel, 7/86
  774.  *        UUCP: ihnp4!umn-cs!hyper!mark, GEnie: mgm
  775.  */
  776.  
  777. /* The CRC polynomial.
  778.  * These 4 values define the crc-polynomial.
  779.  * If you change them, you must change crctab[]'s initial value to what is
  780.  * printed by initcrctab() [see 'compile with -DMAKETAB' above].
  781.  */
  782.     /* Value used by:                CITT    XMODEM    ARC      */
  783. #define    P     0xA001     /* the poly:    0x1021    0x1021    A001    */
  784. #define INIT_CRC 0L     /* init value:    -1    0    0    */
  785. #define SWAPPED         /* bit order:    undef    defined    defined */
  786. #define W    16     /* bits in CRC:16    16    16    */
  787.  
  788.     /* data type that holds a W-bit unsigned integer */
  789. #if W <= 16
  790. #  define WTYPE    unsigned short
  791. #else
  792. #  define WTYPE   unsigned long
  793. #endif
  794.  
  795.     /* the number of bits per char: don't change it. */
  796. #define B    8
  797.  
  798. static WTYPE crctab[1<<B] = /* as calculated by initcrctab() */ {
  799. 0x0,  0xc0c1,  0xc181,  0x140,  0xc301,  0x3c0,  0x280,  0xc241,
  800. 0xc601,  0x6c0,  0x780,  0xc741,  0x500,  0xc5c1,  0xc481,  0x440,
  801. 0xcc01,  0xcc0,  0xd80,  0xcd41,  0xf00,  0xcfc1,  0xce81,  0xe40,
  802. 0xa00,  0xcac1,  0xcb81,  0xb40,  0xc901,  0x9c0,  0x880,  0xc841,
  803. 0xd801,  0x18c0,  0x1980,  0xd941,  0x1b00,  0xdbc1,  0xda81,  0x1a40,
  804. 0x1e00,  0xdec1,  0xdf81,  0x1f40,  0xdd01,  0x1dc0,  0x1c80,  0xdc41,
  805. 0x1400,  0xd4c1,  0xd581,  0x1540,  0xd701,  0x17c0,  0x1680,  0xd641,
  806. 0xd201,  0x12c0,  0x1380,  0xd341,  0x1100,  0xd1c1,  0xd081,  0x1040,
  807. 0xf001,  0x30c0,  0x3180,  0xf141,  0x3300,  0xf3c1,  0xf281,  0x3240,
  808. 0x3600,  0xf6c1,  0xf781,  0x3740,  0xf501,  0x35c0,  0x3480,  0xf441,
  809. 0x3c00,  0xfcc1,  0xfd81,  0x3d40,  0xff01,  0x3fc0,  0x3e80,  0xfe41,
  810. 0xfa01,  0x3ac0,  0x3b80,  0xfb41,  0x3900,  0xf9c1,  0xf881,  0x3840,
  811. 0x2800,  0xe8c1,  0xe981,  0x2940,  0xeb01,  0x2bc0,  0x2a80,  0xea41,
  812. 0xee01,  0x2ec0,  0x2f80,  0xef41,  0x2d00,  0xedc1,  0xec81,  0x2c40,
  813. 0xe401,  0x24c0,  0x2580,  0xe541,  0x2700,  0xe7c1,  0xe681,  0x2640,
  814. 0x2200,  0xe2c1,  0xe381,  0x2340,  0xe101,  0x21c0,  0x2080,  0xe041,
  815. 0xa001,  0x60c0,  0x6180,  0xa141,  0x6300,  0xa3c1,  0xa281,  0x6240,
  816. 0x6600,  0xa6c1,  0xa781,  0x6740,  0xa501,  0x65c0,  0x6480,  0xa441,
  817. 0x6c00,  0xacc1,  0xad81,  0x6d40,  0xaf01,  0x6fc0,  0x6e80,  0xae41,
  818. 0xaa01,  0x6ac0,  0x6b80,  0xab41,  0x6900,  0xa9c1,  0xa881,  0x6840,
  819. 0x7800,  0xb8c1,  0xb981,  0x7940,  0xbb01,  0x7bc0,  0x7a80,  0xba41,
  820. 0xbe01,  0x7ec0,  0x7f80,  0xbf41,  0x7d00,  0xbdc1,  0xbc81,  0x7c40,
  821. 0xb401,  0x74c0,  0x7580,  0xb541,  0x7700,  0xb7c1,  0xb681,  0x7640,
  822. 0x7200,  0xb2c1,  0xb381,  0x7340,  0xb101,  0x71c0,  0x7080,  0xb041,
  823. 0x5000,  0x90c1,  0x9181,  0x5140,  0x9301,  0x53c0,  0x5280,  0x9241,
  824. 0x9601,  0x56c0,  0x5780,  0x9741,  0x5500,  0x95c1,  0x9481,  0x5440,
  825. 0x9c01,  0x5cc0,  0x5d80,  0x9d41,  0x5f00,  0x9fc1,  0x9e81,  0x5e40,
  826. 0x5a00,  0x9ac1,  0x9b81,  0x5b40,  0x9901,  0x59c0,  0x5880,  0x9841,
  827. 0x8801,  0x48c0,  0x4980,  0x8941,  0x4b00,  0x8bc1,  0x8a81,  0x4a40,
  828. 0x4e00,  0x8ec1,  0x8f81,  0x4f40,  0x8d01,  0x4dc0,  0x4c80,  0x8c41,
  829. 0x4400,  0x84c1,  0x8581,  0x4540,  0x8701,  0x47c0,  0x4680,  0x8641,
  830. 0x8201,  0x42c0,  0x4380,  0x8341,  0x4100,  0x81c1,  0x8081,  0x4040,
  831. } ;
  832.  
  833. WTYPE
  834. updcrc( icrc, icp, icnt )
  835.     WTYPE icrc;
  836.     unsigned char *icp;
  837.     int icnt;
  838. {
  839.     register WTYPE crc = icrc;
  840.     register unsigned char *cp = icp;
  841.     register int cnt = icnt;
  842.  
  843.     while( cnt-- ) {
  844. #ifndef SWAPPED
  845.     crc = (crc<<B) ^ crctab[(crc>>(W-B)) ^ *cp++];
  846. #else
  847.     crc = (crc>>B) ^ crctab[(crc & ((1<<B)-1)) ^ *cp++]; 
  848. #endif SWAPPED
  849.     }
  850.  
  851.     return( crc );
  852. }
  853.  
  854. #ifdef MAKETAB
  855.  
  856. #include <stdio.h>
  857. main()
  858. {
  859.     initcrctab();
  860. }
  861.  
  862. initcrctab()
  863. {
  864.     register  int b, i;
  865.     WTYPE v;
  866.  
  867.     
  868.     for( b = 0; b <= (1<<B)-1; ++b ) {
  869. #ifndef SWAPPED
  870.     for( v = b<<(W-B), i = B; --i >= 0; )
  871.         v = v & ((WTYPE)1<<(W-1)) ? (v<<1)^P : v<<1;
  872. #else
  873.     for( v = b, i = B; --i >= 0; )
  874.         v = v & 1 ? (v>>1)^P : v>>1;
  875. #endif        
  876.     crctab[b] = v;
  877.  
  878.     printf( "0x%lx,", v & ((1L<<W)-1L));
  879.     if( (b&7) == 7 )
  880.         printf("\n" );
  881.     else
  882.         printf("  ");
  883.     }
  884. }
  885. #endif
  886.  
  887. #ifdef TEST
  888.  
  889. #include <stdio.h>
  890. #include <fcntl.h>
  891.  
  892. #define MAXBUF    4096
  893.  
  894.  
  895.  
  896. main( ac, av )
  897.     int ac; char **av;
  898. {
  899.     int fd;
  900.     int nr;
  901.     int i;
  902.     char buf[MAXBUF];
  903.     WTYPE crc, crc2;
  904.  
  905.     fd = 0;
  906.     if( ac > 1 )
  907.     if( (fd = open( av[1], O_RDONLY )) < 0 ) {
  908.         perror( av[1] );
  909.         exit( -1 );
  910.     }
  911.     crc = crc2 = INIT_CRC;
  912.  
  913.     while( (nr = read( fd, buf, MAXBUF )) > 0 ) {
  914.     crc = updcrc( crc, buf, nr );
  915.     }
  916.  
  917.     if( nr != 0 )
  918.     perror( "reading" );
  919.     else {
  920.     printf( "%lx\n", crc );
  921.     }
  922.  
  923. #ifdef MAGICCHECK
  924.     /* tack one's complement of crc onto data stream, and
  925.        continue crc calculation.  Should get a constant (magic number)
  926.        dependent only on P, not the data.
  927.      */
  928.     crc2 = crc ^ -1L;
  929.     for( nr = W-B; nr >= 0; nr -= B ) {
  930.     buf[0] = (crc2 >> nr);
  931.     crc = updcrc(crc, buf, 1);
  932.     }
  933.  
  934.     /* crc should now equal magic */
  935.     buf[0] = buf[1] = buf[2] = buf[3] = 0;
  936.     printf( "magic test: %lx =?= %lx\n", crc, updcrc(-1, buf, W/B));
  937. #endif MAGICCHECK
  938. }
  939.  
  940. #endif
  941.  
  942. @//E*O*F unsit.c//
  943. chmod u=rw,g=r,o=r unsit.c
  944.  
  945. echo x - unsit.h
  946. sed 's/^@//' > "unsit.h" <<'@//E*O*F unsit.h//'
  947. /* unsit.h: contains declarations for SIT headers */
  948.  
  949. typedef struct sitHdr {            /* 22 bytes */
  950.     OSType    signature;         /* = 'SIT!' -- for verification */
  951.     unsigned short    numFiles;    /* number of files in archive */
  952.     unsigned long    arcLength;    /* length of entire archive incl.
  953.                         hdr. -- for verification */
  954.     OSType    signature2;        /* = 'rLau' -- for verification */
  955.     unsigned char    version;    /* version number */
  956.     char reserved[7];
  957. };
  958.  
  959. typedef struct fileHdr {        /* 112 bytes */
  960.     unsigned char    compRMethod;    /* rsrc fork compression method */
  961.     unsigned char    compDMethod;    /* data fork compression method */
  962.     unsigned char    fName[64];    /* a STR63 */
  963.     OSType    fType;            /* file type */
  964.     OSType    fCreator;        /* er... */
  965.     short FndrFlags;        /* copy of Finder flags.  For our
  966.                         purposes, we can clear:
  967.                         busy,onDesk */
  968.     unsigned long    creationDate;
  969.     unsigned long    modDate;    /* !restored-compat w/backup prgms */
  970.     unsigned long    rsrcLength;    /* decompressed lengths */
  971.     unsigned long    dataLength;
  972.     unsigned long    compRLength;    /* compressed lengths */
  973.     unsigned long    compDLength;
  974.     unsigned short rsrcCRC;        /* crc of rsrc fork */
  975.     unsigned short dataCRC;        /* crc of data fork */
  976.     char reserved[6];
  977.     unsigned short hdrCRC;        /* crc of file header */
  978. };
  979.  
  980.  
  981. /* file format is:
  982.     sitArchiveHdr
  983.         file1Hdr
  984.             file1RsrcFork
  985.             file1DataFork
  986.         file2Hdr
  987.             file2RsrcFork
  988.             file2DataFork
  989.         .
  990.         .
  991.         .
  992.         fileNHdr
  993.             fileNRsrcFork
  994.             fileNDataFork
  995. */
  996.  
  997.  
  998.  
  999. /* compression methods */
  1000. #define noComp     0    /* just read each byte and write it to archive */
  1001. #define repComp 1    /* RLE compression */
  1002. #define lpzComp 2    /* LZW compression */
  1003. #define hufComp 3    /* Huffman compression */
  1004.  
  1005. /* all other numbers are reserved */
  1006. @//E*O*F unsit.h//
  1007. chmod u=rw,g=r,o=r unsit.h
  1008.  
  1009. exit 0
  1010.