home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / UNARJ.LZH / UNARJ.C < prev    next >
C/C++ Source or Header  |  1991-12-28  |  23KB  |  1,029 lines

  1. /* UNARJ.C, UNARJ, R JUNG, 05/25/91
  2.  * Main Extractor routine
  3.  * Copyright (c) 1991 by Robert K Jung.  All rights reserved.
  4.  *
  5.  *   This code may be freely used in programs that are NOT archivers.
  6.  *
  7.  *   If you wish to distribute a modified version of this program, you
  8.  *   must include the source code.
  9.  *
  10.  *   If you modify this program, I would appreciate a copy of the new
  11.  *   source code.  I am holding the copyright on the source code, so
  12.  *   please do not delete my name from the program files or from the
  13.  *   documentation.
  14.  *
  15.  *   I wish to give credit to Haruhiko Okumura for providing the
  16.  *   basic ideas for ARJ and UNARJ in his program AR.  Please note
  17.  *   that UNARJ is significantly different from AR from an archive
  18.  *   structural point of view.
  19.  *
  20.  * Modification history:
  21.  * Date      Programmer  Description of modification.
  22.  * 04/05/91  R. Jung     Rewrote code.
  23.  * 04/23/91  M. Adler     Portabilized.
  24.  * 04/29/91  R. Jung     Added l command.  Removed 16 bit dependency in
  25.  *             fillbuf().
  26.  * 05/19/91  R. Jung     Fixed extended header skipping code.
  27.  * 05/25/91  R. Jung     Improved find_header().
  28.  * 12/28/91  S. Dudley   Added support for filename lists
  29.  *
  30.  */
  31.  
  32. #include "unarj.h"
  33.  
  34. #ifdef MODERN
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38. #else /* !MODERN */
  39. extern void free();
  40. extern void exit();
  41. extern char *strcat();
  42. extern char *strcpy();
  43. extern char *strncpy();
  44. extern char *strchr();
  45. extern char *strrchr();
  46. extern int strlen();
  47. extern int strcmp();
  48. #define EXIT_FAILURE (1)
  49. #define EXIT_SUCCESS (0)
  50. #define toupper(c) ((c)>='a'&&(c)<='z'?(c)-('a'-'A'):(c))
  51. #endif /* ?MODERN */
  52.  
  53. /* Global variables */
  54.  
  55. UCRC   crc;
  56. FILE   *arcfile;
  57. FILE   *outfile;
  58. ushort bitbuf;
  59. long   compsize;
  60. long   origsize;
  61. uchar  subbitbuf;
  62. uchar  header[HEADERSIZE_MAX];
  63. char   arc_name[FNAME_MAX];
  64. int    command;
  65. int    bitcount;
  66. int    file_type;
  67. int    no_output;
  68. int    error_count;
  69.  
  70. /* Messages */
  71.  
  72. static char *M_USAGE  [] =
  73. {
  74. "Usage:  UNARJ archive[.arj]              (list archive)\n",
  75. "        UNARJ e archive  [files...]      (extract archive)\n",
  76. "        UNARJ l archive  [files...]      (list archive)\n",
  77. "        UNARJ t archive  [files...]      (test archive)\n",
  78. "        UNARJ x archive  [files...]      (extract with pathnames)\n",
  79. "\n",
  80. "This is an ARJ demonstration program and ** IS NOT OPTIMIZED ** for speed.\n",
  81. "You may freely use, copy and distribute this program, provided that no fee\n",
  82. "is charged for such use, copying or distribution, and it is distributed\n",
  83. "ONLY in its original unmodified state.  UNARJ is provided as is without\n",
  84. "warranty of any kind, expressed or implied, including but not limited to\n",
  85. "the implied warranties of merchantability and fitness for a particular\n",
  86. "purpose.  Refer to UNARJ.DOC for more warranty information.  If you find\n",
  87. "UNARJ of value, a gift of $10 or any amount would greatly appreciated.\n",
  88. "\n",
  89. "Robert K Jung                   Internet address :  robjung@world.std.com\n",
  90. "2606 Village Road West          CompuServe userid:  72077,445\n",
  91. "Norwood, Massachusetts 02062\n",
  92. "USA\n",
  93. NULL
  94. };
  95.  
  96. char M_VERSION [] = "UNARJ (Demo version) 2.10 Copyright (c) 1991 Robert K Jung\n\n";
  97.  
  98. char M_ARCDATE [] = "Archive date      : %s\n";
  99. char M_BADCOMND[] = "Bad UNARJ command: %s";
  100. char M_BADCOMNT[] = "Invalid comment header";
  101. char M_BADHEADR[] = "Bad header";
  102. char M_BADTABLE[] = "Bad Huffman code";
  103. char M_CANTOPEN[] = "Can't open %s";
  104. char M_CANTREAD[] = "Can't read file or unexpected end of file";
  105. char M_CANTWRIT[] = "Can't write file. Disk full?";
  106. char M_CRCERROR[] = "CRC error!\n";
  107. char M_CRCOK   [] = "CRC OK\n";
  108. char M_DIFFHOST[] = ", Warning! Binary file from a different OS";
  109. char M_ENCRYPT [] = "File is password encrypted, ";
  110. char M_ERRORCNT[] = "%sFound %5d error(s)!";
  111. char M_EXTRACT [] = "Extracting %-25s";
  112. char M_FEXISTS [] = "%-25s exists, ";
  113. char M_HEADRCRC[] = "Header CRC error!";
  114. char M_NBRFILES[] = "%5d file(s)\n";
  115. char M_NOMEMORY[] = "Out of memory";
  116. char M_NOTARJ  [] = "%s is not an ARJ archive";
  117. char M_PROCARC [] = "Processing archive: %s\n";
  118. char M_SKIPPED [] = "Skipped %s\n";
  119. char M_SUFFIX  [] = ARJ_SUFFIX;
  120. char M_TESTING [] = "Testing    %-25s";
  121. char M_UNKNMETH[] = "Unsupported method: %d, ";
  122. char M_UNKNTYPE[] = "Unsupported file type: %d, ";
  123. char M_UNKNVERS[] = "Unsupported version: %d, ";
  124.  
  125. #define get_crc()    get_longword()
  126. #define fget_crc(f)    fget_longword(f)
  127.  
  128. #define setup_get(PTR)    (get_ptr = (PTR))
  129. #define get_byte()    ((uchar)(*get_ptr++ & 0xff))
  130.  
  131. #define BUFFERSIZE    4096
  132.  
  133. #define ASCII_MASK    0x7F
  134.  
  135. #define CRCPOLY     0xEDB88320L
  136.  
  137. #define UPDATE_CRC(r,c) r=crctable[((uchar)(r)^(uchar)(c))&0xff]^(r>>CHAR_BIT)
  138.  
  139. /* Local functions */
  140.  
  141. #ifdef MODERN
  142. static void  make_crctable(void);
  143. static void  crc_buf(char *str, int len);
  144. static void  strparity(uchar *p);
  145. static FILE  *fopen_msg(char *name, char *mode);
  146. static int   fget_byte(FILE *f);
  147. static uint  fget_word(FILE *f);
  148. static ulong fget_longword(FILE *f);
  149. static void  fread_crc(uchar *p, int n, FILE *f);
  150. static void  decode_path(char *name);
  151. static void  get_date_str(char *str, ulong tstamp);
  152. static int   parse_path(char *pathname, char *path, char *entry);
  153. static void  strncopy(char *to, char *from, int len);
  154. static uint  get_word(void);
  155. static ulong get_longword(void);
  156. static long  find_header(FILE *fd);
  157. static int   read_header(int first, FILE *fd, char *name);
  158. static void  skip(void);
  159. static void  unstore(void);
  160. static int   check_flags(void);
  161. static int   extract(void);
  162. static int   test(void);
  163. static uint  ratio(long a, long b);
  164. static void  list_start(void);
  165. static void  list_arc(int count);
  166. static void  execute_cmd(char **list); /*SJD Sat  12-28-1991  14:26:53 */
  167. static void  help(void);
  168. static int MatchWC(char *pat, char *fn); /*SJD Sat  12-28-1991  14:35:57 */
  169. #endif /* MODERN */
  170.  
  171. /* Local variables */
  172.  
  173. static char   filename[FNAME_MAX];
  174. static char   comment[COMMENT_MAX];
  175. static char   *hdr_filename;
  176. static char   *hdr_comment;
  177.  
  178. static ushort headersize;
  179. static uchar  first_hdr_size;
  180. static uchar  arj_nbr;
  181. static uchar  arj_x_nbr;
  182. static uchar  host_os;
  183. static uchar  arj_flags;
  184. static short  method;
  185. static uint   file_mode;
  186. static ulong  time_stamp;
  187. static short  entry_pos;
  188. static ushort host_data;
  189. static uchar  *get_ptr;
  190. static UCRC   file_crc;
  191. static UCRC   header_crc;
  192.  
  193. static long   first_hdr_pos;
  194. static long   torigsize;
  195. static long   tcompsize;
  196.  
  197. static int    clock_inx;
  198.  
  199. static char   *writemode[2]  = { "wb",    "w" };
  200.  
  201. static UCRC   crctable[UCHAR_MAX + 1];
  202.  
  203. /* Functions */
  204.  
  205. static void
  206. make_crctable()
  207. {
  208.     uint i, j;
  209.     UCRC r;
  210.  
  211.     for (i = 0; i <= UCHAR_MAX; i++)
  212.     {
  213.     r = i;
  214.     for (j = CHAR_BIT; j > 0; j--)
  215.     {
  216.         if (r & 1)
  217.         r = (r >> 1) ^ CRCPOLY;
  218.         else
  219.         r >>= 1;
  220.     }
  221.     crctable[i] = r;
  222.     }
  223. }
  224.  
  225. static void
  226. crc_buf(str, len)
  227. char *str;
  228. int  len;
  229. {
  230.     while (len--)
  231.     UPDATE_CRC(crc, *str++);
  232. }
  233.  
  234. void
  235. disp_clock()
  236. {
  237.     static char clock_str[4] = { '|', '/', '-', '\\' };
  238.  
  239.     printf("(%c)\b\b\b", clock_str[clock_inx]);
  240.     clock_inx = (clock_inx + 1) & 0x03;
  241. }
  242.  
  243. void
  244. error(fmt, arg)
  245. char *fmt;
  246. char *arg;
  247. {
  248.     putc('\n', stdout);
  249.     printf(fmt, arg, error_count);
  250.     putc('\n', stdout);
  251.     exit(EXIT_FAILURE);
  252. }
  253.  
  254. static void
  255. strparity(p)
  256. uchar *p;
  257. {
  258.     while (*p)
  259.     {
  260.     FIX_PARITY(*p);
  261.     p++;
  262.     }
  263. }
  264.  
  265. static FILE *
  266. fopen_msg(name, mode)
  267. char *name;
  268. char *mode;
  269. {
  270.     FILE *fd;
  271.  
  272.     fd = file_open(name, mode);
  273.     if (fd == NULL)
  274.     error(M_CANTOPEN, name);
  275.     return fd;
  276. }
  277.  
  278. static int
  279. fget_byte(f)
  280. FILE *f;
  281. {
  282.     int c;
  283.  
  284.     if ((c = getc(f)) == EOF)
  285.     error(M_CANTREAD, "");
  286.     return c & 0xFF;
  287. }
  288.  
  289. static uint
  290. fget_word(f)
  291. FILE *f;
  292. {
  293.     uint b0, b1;
  294.  
  295.     b0 = fget_byte(f);
  296.     b1 = fget_byte(f);
  297.     return (b1 << 8) + b0;
  298. }
  299.  
  300. static ulong
  301. fget_longword(f)
  302. FILE *f;
  303. {
  304.     ulong b0, b1, b2, b3;
  305.  
  306.     b0 = fget_byte(f);
  307.     b1 = fget_byte(f);
  308.     b2 = fget_byte(f);
  309.     b3 = fget_byte(f);
  310.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  311. }
  312.  
  313. static void
  314. fread_crc(p, n, f)
  315. uchar *p;
  316. int   n;
  317. FILE  *f;
  318. {
  319.     n = file_read((char *)p, 1, n, f);
  320.     origsize += n;
  321.     crc_buf((char *)p, n);
  322. }
  323.  
  324. void
  325. fwrite_txt_crc(p, n)
  326. uchar *p;
  327. int   n;
  328. {
  329.     uchar c;
  330.  
  331.     crc_buf((char *)p, n);
  332.     if (no_output)
  333.     return;
  334.  
  335.     if (file_type == TEXT_TYPE)
  336.     {
  337.     while (n--)
  338.     {
  339.         c = *p++;
  340.         FIX_PARITY(c);
  341.         if (putc((int) c, outfile) == EOF)
  342.         error(M_CANTWRIT, "");
  343.     }
  344.     }
  345.     else
  346.     {
  347.     if (file_write((char *)p, 1, n, outfile) != n)
  348.         error(M_CANTWRIT, "");
  349.     }
  350. }
  351.  
  352. void
  353. init_getbits()
  354. {
  355.     bitbuf = 0;
  356.     subbitbuf = 0;
  357.     bitcount = 0;
  358.     fillbuf(2 * CHAR_BIT);
  359. }
  360.  
  361. void
  362. fillbuf(n)          /* Shift bitbuf n bits left, read n bits */
  363. int n;
  364. {
  365.     bitbuf = (bitbuf << n) & 0xFFFF;  /* lose the first n bits */
  366.     while (n > bitcount)
  367.     {
  368.     bitbuf |= subbitbuf << (n -= bitcount);
  369.     if (compsize != 0)
  370.     {
  371.         compsize--;
  372.         subbitbuf = (uchar) getc(arcfile);
  373.     }
  374.     else
  375.         subbitbuf = 0;
  376.     bitcount = CHAR_BIT;
  377.     }
  378.     bitbuf |= subbitbuf >> (bitcount -= n);
  379. }
  380.  
  381. ushort
  382. getbits(n)
  383. int n;
  384. {
  385.     ushort x;
  386.  
  387.     x = bitbuf >> (2 * CHAR_BIT - n);
  388.     fillbuf(n);
  389.     return x;
  390. }
  391.  
  392. static void
  393. decode_path(name)
  394. char *name;
  395. {
  396.     for ( ; *name; name++)
  397.     {
  398.     if (*name == ARJ_PATH_CHAR)
  399.         *name = PATH_CHAR;
  400.     }
  401. }
  402.  
  403. static void
  404. get_date_str(str, tstamp)
  405. char  *str;
  406. ulong tstamp;
  407. {
  408.     sprintf(str, "%04u-%02u-%02u %02u:%02u:%02u",
  409.        ts_year(tstamp), ts_month(tstamp), ts_day(tstamp),
  410.        ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
  411. }
  412.  
  413. static int
  414. parse_path(pathname, path, entry)
  415. char *pathname;
  416. char *path;
  417. char *entry;
  418. {
  419.     char *cptr, *ptr, *fptr;
  420.     short pos;
  421.  
  422.     fptr = NULL;
  423.     for (cptr = PATH_SEPARATORS; *cptr; cptr++)
  424.     {
  425.     if ((ptr = strrchr(pathname, *cptr)) != NULL &&
  426.         (fptr == NULL || ptr > fptr))
  427.         fptr = ptr;
  428.     }
  429.     if (fptr == NULL)
  430.     pos = 0;
  431.     else
  432.     pos = fptr + 1 - pathname;
  433.     if (path != NULL)
  434.     {
  435.        strncpy(path, pathname, pos);
  436.        path[pos] = NULL_CHAR;
  437.     }
  438.     if (entry != NULL)
  439.        strcpy(entry, &pathname[pos]);
  440.     return pos;
  441. }
  442.  
  443. static void
  444. strncopy(to, from, len)
  445. char *to;
  446. char *from;
  447. int  len;
  448. {
  449.     int i;
  450.  
  451.     for (i = 1; i < len && *from; i++)
  452.     *to++ = *from++;
  453.     *to = NULL_CHAR;
  454. }
  455.  
  456. void
  457. strupper(s)
  458. char *s;
  459. {
  460.     while (*s)
  461.     {
  462.     *s = (char)toupper(*s);
  463.     s++;
  464.     }
  465. }
  466.  
  467. voidp *
  468. malloc_msg(size)
  469. int size;
  470. {
  471.     char *p;
  472.  
  473.     if ((p = (char *)xmalloc(size)) == NULL)
  474.     error(M_NOMEMORY, "");
  475.     return (voidp *)p;
  476. }
  477.  
  478. static uint
  479. get_word()
  480. {
  481.     uint b0, b1;
  482.  
  483.     b0 = get_byte();
  484.     b1 = get_byte();
  485.     return (b1 << 8) + b0;
  486. }
  487.  
  488. static ulong
  489. get_longword()
  490. {
  491.     ulong b0, b1, b2, b3;
  492.  
  493.     b0 = get_byte();
  494.     b1 = get_byte();
  495.     b2 = get_byte();
  496.     b3 = get_byte();
  497.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  498. }
  499.  
  500. static long
  501. find_header(fd)
  502. FILE *fd;
  503. {
  504.     long arcpos, lastpos;
  505.     int c;
  506.  
  507.     arcpos = file_tell(fd);
  508.     file_seek(fd, 0L, SEEK_END);
  509.     lastpos = file_tell(fd) - 2;
  510.     if (lastpos > MAXSFX)
  511.     lastpos = MAXSFX;
  512.     for ( ; arcpos < lastpos; arcpos++)
  513.     {
  514.     file_seek(fd, arcpos, SEEK_SET);
  515.     c = fget_byte(fd);
  516.     while (arcpos < lastpos)
  517.     {
  518.         if (c != HEADER_ID_LO)  /* low order first */
  519.         c = fget_byte(fd);
  520.         else if ((c = fget_byte(fd)) == HEADER_ID_HI)
  521.         break;
  522.         arcpos++;
  523.     }
  524.     if (arcpos >= lastpos)
  525.         break;
  526.     if ((headersize = fget_word(fd)) <= HEADERSIZE_MAX)
  527.     {
  528.         crc = CRC_MASK;
  529.         fread_crc(header, (int) headersize, fd);
  530.         if ((crc ^ CRC_MASK) == fget_crc(fd))
  531.         {
  532.         file_seek(fd, arcpos, SEEK_SET);
  533.         return arcpos;
  534.         }
  535.     }
  536.     }
  537.     return -1;        /* could not find a valid header */
  538. }
  539.  
  540. static int
  541. read_header(first, fd, name)
  542. int  first;
  543. FILE *fd;
  544. char *name;
  545. {
  546.     ushort extheadersize, header_id;
  547.  
  548.     header_id = fget_word(fd);
  549.     if (header_id != HEADER_ID)
  550.     {
  551.     if (first)
  552.         error(M_NOTARJ, name);
  553.     else
  554.         error(M_BADHEADR, "");
  555.     }
  556.  
  557.     headersize = fget_word(fd);
  558.     if (headersize == 0)
  559.     return 0;        /* end of archive */
  560.     if (headersize > HEADERSIZE_MAX)
  561.     error(M_BADHEADR, "");
  562.  
  563.     crc = CRC_MASK;
  564.     fread_crc(header, (int) headersize, fd);
  565.     header_crc = fget_crc(fd);
  566.     if ((crc ^ CRC_MASK) != header_crc)
  567.     error(M_HEADRCRC, "");
  568.  
  569.     setup_get(header);
  570.     first_hdr_size = get_byte();
  571.     arj_nbr = get_byte();
  572.     arj_x_nbr = get_byte();
  573.     host_os = get_byte();
  574.     arj_flags = get_byte();
  575.     method = get_byte();
  576.     file_type = get_byte();
  577.     (void)get_byte();
  578.     time_stamp = get_longword();
  579.     compsize = get_longword();
  580.     origsize = get_longword();
  581.     file_crc = get_crc();
  582.     entry_pos = get_word();
  583.     file_mode = get_word();
  584.     host_data = get_word();
  585.  
  586.     hdr_filename = (char *)&header[first_hdr_size];
  587.     strncopy(filename, hdr_filename, sizeof(filename));
  588.     if (host_os != OS)
  589.     strparity((uchar *)filename);
  590.     if ((arj_flags & PATHSYM_FLAG) != 0)
  591.     decode_path(filename);
  592.  
  593.     hdr_comment = (char *)&header[first_hdr_size + strlen(hdr_filename) + 1];
  594.     strncopy(comment, hdr_comment, sizeof(comment));
  595.     if (host_os != OS)
  596.     strparity((uchar *)comment);
  597.  
  598.     /* if extheadersize == 0 then no CRC */
  599.     /* otherwise read extheader data and read 4 bytes for CRC */
  600.  
  601.     while ((extheadersize = fget_word(fd)) != 0)
  602.     file_seek(fd, (long) (extheadersize + 4), SEEK_CUR);
  603.  
  604.     return 1;            /* success */
  605. }
  606.  
  607. static void
  608. skip()
  609. {
  610.     file_seek(arcfile, compsize, SEEK_CUR);
  611. }
  612.  
  613. static void
  614. unstore()
  615. {
  616.     int n;
  617.     long pos;
  618.     char *buffer;
  619.  
  620.     buffer = (char *)malloc_msg(BUFFERSIZE);
  621.     pos = file_tell(arcfile);
  622.     disp_clock();
  623.     n = (int)(BUFFERSIZE - (pos % BUFFERSIZE));
  624.     n = compsize > (long)n ? n : (int)compsize;
  625.     while (compsize > 0)
  626.     {
  627.     if (file_read(buffer, 1, n, arcfile) != n)
  628.         error(M_CANTREAD, "");
  629.     disp_clock();
  630.     compsize -= n;
  631.     fwrite_txt_crc((uchar *)buffer, n);
  632.     n = compsize > BUFFERSIZE ? BUFFERSIZE : (int)compsize;
  633.     }
  634.     free(buffer);
  635. }
  636.  
  637. static int
  638. check_flags()
  639. {
  640.     if (arj_x_nbr > ARJ_X_VERSION)
  641.     {
  642.     printf(M_UNKNVERS, arj_x_nbr);
  643.     printf(M_SKIPPED, filename);
  644.     skip();
  645.     return -1;
  646.     }
  647.     if ((arj_flags & GARBLE_FLAG) != 0)
  648.     {
  649.     printf(M_ENCRYPT);
  650.     printf(M_SKIPPED, filename);
  651.     skip();
  652.     return -1;
  653.     }
  654.     if (method < 0 || method > MAXMETHOD || (method == 4 && arj_nbr == 1))
  655.     {
  656.     printf(M_UNKNMETH, method);
  657.     printf(M_SKIPPED, filename);
  658.     skip();
  659.     return -1;
  660.     }
  661.     if (file_type != BINARY_TYPE && file_type != TEXT_TYPE)
  662.     {
  663.     printf(M_UNKNTYPE, file_type);
  664.     printf(M_SKIPPED, filename);
  665.     skip();
  666.     return -1;
  667.     }
  668.     return 0;
  669. }
  670.  
  671. static int
  672. extract()
  673. {
  674.     char name[FNAME_MAX];
  675.  
  676.     if (check_flags())
  677.     return 0;
  678.  
  679.     no_output = 0;
  680.     if (command == 'E')
  681.     strcpy(name, &filename[entry_pos]);
  682.     else
  683.     {
  684.     strcpy(name, DEFAULT_DIR);
  685.     strcat(name, filename);
  686.     }
  687.     if (file_exists(name))
  688.     {
  689.     printf(M_FEXISTS, name);
  690.     printf(M_SKIPPED, name);
  691.     skip();
  692.     return 0;
  693.     }
  694.     outfile = file_open(name, writemode[file_type & 1]);
  695.     if (outfile == NULL)
  696.     {
  697.     printf(M_CANTOPEN, name);
  698.     putchar('\n');
  699.     skip();
  700.     return 0;
  701.     }
  702.     printf(M_EXTRACT, name);
  703.     if (host_os != OS && file_type == BINARY_TYPE)
  704.     printf(M_DIFFHOST);
  705.     printf("  ");
  706.  
  707.     crc = CRC_MASK;
  708.  
  709.     if (method == 0)
  710.     unstore();
  711.     else if (method == 1 || method == 2 || method == 3)
  712.     decode();
  713.     else if (method == 4)
  714.     decode_f();
  715.     fclose(outfile);
  716.  
  717.     set_ftime_mode(name, time_stamp, file_mode, host_os);
  718.  
  719.     if ((crc ^ CRC_MASK) == file_crc)
  720.     printf(M_CRCOK);
  721.     else
  722.     {
  723.     printf(M_CRCERROR);
  724.     error_count++;
  725.     }
  726.     return 1;
  727. }
  728.  
  729. static int
  730. test()
  731. {
  732.     if (check_flags())
  733.     return 0;
  734.  
  735.     no_output = 1;
  736.     printf(M_TESTING, filename);
  737.     printf("  ");
  738.  
  739.     crc = CRC_MASK;
  740.  
  741.     if (method == 0)
  742.     unstore();
  743.     else if (method == 1 || method == 2 || method == 3)
  744.     decode();
  745.     else if (method == 4)
  746.     decode_f();
  747.  
  748.     if ((crc ^ CRC_MASK) == file_crc)
  749.     printf(M_CRCOK);
  750.     else
  751.     {
  752.     printf(M_CRCERROR);
  753.     error_count++;
  754.     }
  755.     return 1;
  756. }
  757.  
  758. uint
  759. ratio(a, b)
  760. long a, b;
  761. {
  762.    int i;
  763.  
  764.    for (i = 0; i < 3; i++)
  765.        if (a <= LONG_MAX / 10)
  766.        a *= 10;
  767.        else
  768.        b /= 10;
  769.    if ((long) (a + (b >> 1)) < a)
  770.    {
  771.        a >>= 1;
  772.        b >>= 1;
  773.    }
  774.    if (b == 0)
  775.        return 0;
  776.    return (uint) ((a + (b >> 1)) / b);
  777. }
  778.  
  779. static void
  780. list_start()
  781. {
  782.     printf("Filename       Original Compressed Ratio DateTime modified CRC-32   Attr TPMGVX\n");
  783.     printf("------------ ---------- ---------- ----- ----------------- -------- ---- ------\n");
  784. }
  785.  
  786. static void
  787. list_arc(count)
  788. int count;
  789. {
  790.     uint r;
  791.     int garble_mode, path_mode, volume_mode, extfil_mode, ftype;
  792.     char date_str[20], fmode_str[10];
  793.     static char mode[5] = { 'B', 'T', '?', 'D', 'V' };
  794.     static char pthf[2] = { ' ', '+' };
  795.     static char pwdf[2] = { ' ', 'G' };  /* plain, encrypted */
  796.     static char volf[2] = { ' ', 'V' };
  797.     static char extf[2] = { ' ', 'X' };
  798.  
  799.     if (count == 0)
  800.     list_start();
  801.  
  802.     garble_mode = ((arj_flags & GARBLE_FLAG) != 0);
  803.     volume_mode = ((arj_flags & VOLUME_FLAG) != 0);
  804.     extfil_mode = ((arj_flags & EXTFILE_FLAG) != 0);
  805.     path_mode = (entry_pos > 0);
  806.     r = ratio(compsize, origsize);
  807.     torigsize += origsize;
  808.     tcompsize += compsize;
  809.     ftype = file_type;
  810.     if (ftype != BINARY_TYPE && ftype != TEXT_TYPE && ftype != DIR_TYPE &&
  811.         ftype != LABEL_TYPE)
  812.     ftype = 3;
  813.     get_date_str(date_str, time_stamp);
  814.     strcpy(fmode_str, "    ");
  815.     if (host_os == OS)
  816.     get_mode_str(fmode_str, file_mode);
  817.     if (strlen(&filename[entry_pos]) > 12)
  818.     printf("%-12s\n             ", &filename[entry_pos]);
  819.     else
  820.     printf("%-12s ", &filename[entry_pos]);
  821.     printf("%10ld %10ld %u.%03u %s %08lX %4s %c%c%u%c\n",
  822.     origsize, compsize, r / 1000, r % 1000, &date_str[2], file_crc,
  823.     fmode_str, mode[ftype], pthf[path_mode], method, pwdf[garble_mode],
  824.     volf[volume_mode], extf[extfil_mode]);
  825. }
  826.  
  827.  
  828. static int /*SJD Sat  12-28-1991  14:30:14 */
  829. MatchWC(pat, fn) /*SJD Sat  12-28-1991  14:30:14 */
  830.   char *pat, *fn; /*SJD Sat  12-28-1991  14:30:14 */
  831. {
  832.   while (*pat && *fn)
  833.   {
  834.     if (*pat=='*' || *fn=='*')
  835.     {
  836. /*    if (*fn != '.')
  837.         fn++; */
  838.  
  839.       while (*fn && *fn != '.')
  840.         fn++;
  841.       
  842.       if (*pat != '.')
  843.         pat++;
  844.       
  845.        while (*pat && *pat != '.')
  846.         pat++;
  847.     }
  848.     else if (*pat=='?' || *fn=='?')
  849.     {
  850.       if (*pat != '.')
  851.         pat++;
  852.       
  853.       if (*fn != '.')
  854.         fn++;
  855.     }
  856.     else
  857.     {
  858.       int ch1=toupper(*pat);
  859.       int ch2=toupper(*fn);
  860.       pat++;
  861.       fn++;
  862.  
  863.       if (ch1 != ch2)
  864.         return 0;
  865.  
  866.       /* !@#$!@#$ msc bugs.  ANSI says that toupper() can only evaluate
  867.          its argument once!
  868.  
  869.       if (toupper(*pat++) != toupper(*fn++))
  870.       {
  871.         return 0;
  872.       }
  873.       */
  874.     }
  875.   }
  876.   
  877.   return (*pat=='\0' && *fn=='\0');
  878. }
  879.  
  880. static void
  881. execute_cmd(list) /*SJD Sat  12-28-1991  14:27:04 */
  882.   char **list;
  883. {
  884.     int file_count;
  885.     char date_str[22];
  886.     char **lp; /*SJD Sat  12-28-1991  14:31:29 */
  887.     int doit; /*SJD Sat  12-28-1991  14:31:54 */
  888.     uint r;
  889.  
  890.     first_hdr_pos = 0;
  891.     time_stamp = 0;
  892.     first_hdr_size = FIRST_HDR_SIZE;
  893.  
  894.     arcfile = fopen_msg(arc_name, "rb");
  895.  
  896.     printf(M_PROCARC, arc_name);
  897.  
  898.     first_hdr_pos = find_header(arcfile);
  899.     if (first_hdr_pos < 0)
  900.     error(M_NOTARJ, arc_name);
  901.     file_seek(arcfile, first_hdr_pos, SEEK_SET);
  902.     if (!read_header(1, arcfile, arc_name))
  903.     error(M_BADCOMNT, "");
  904.     get_date_str(date_str, time_stamp);
  905.     printf(M_ARCDATE, date_str);
  906.  
  907.     file_count = 0;
  908.     while (read_header(0, arcfile, arc_name))
  909.     {
  910.      /*SJD Sat  12-28-1991  14:36:03  begin modifications */
  911.  
  912.       doit=0;
  913.  
  914.       if (*list==NULL)
  915.         doit=1;
  916.       else for (lp=list; *lp; lp++)
  917.         if (MatchWC(*lp, filename+entry_pos))
  918.         {
  919.           doit=1;
  920.           break;
  921.         }
  922.  
  923.       if (!doit) 
  924.         skip();
  925.       else switch (command)/*SJD Sat  12-28-1991  14:36:16  end modifications*/
  926.     {
  927.     case 'E':
  928.     case 'X':
  929.         if (extract())
  930.         file_count++;
  931.         break;
  932.     case 'L':
  933.         list_arc(file_count++);
  934.         skip();
  935.         break;
  936.     case 'T':
  937.         if (test())
  938.         file_count++;
  939.         break;
  940.     }
  941.     }
  942.  
  943.     if (command == 'L')
  944.     {
  945.     printf("------------ ---------- ---------- ----- -----------------\n");
  946.     r = ratio(tcompsize, torigsize);
  947.     printf(" %5d files %10ld %10ld %u.%03u %s\n",
  948.         file_count, torigsize, tcompsize, r / 1000, r % 1000, &date_str[2]);
  949.     }
  950.     else
  951.     printf(M_NBRFILES, file_count);
  952.  
  953.     fclose(arcfile);
  954. }
  955.  
  956. static void
  957. help()
  958. {
  959.     int i;
  960.  
  961.     for (i = 0; M_USAGE[i] != NULL; i++)
  962.     printf(M_USAGE[i]);
  963. }
  964.  
  965. int
  966. main(argc, argv)
  967. int  argc;
  968. char *argv[];
  969. {
  970.     int i, j, lastc;
  971.     char *arc_p;
  972.     char **list=NULL;
  973.  
  974.     printf(M_VERSION);
  975.  
  976.     if (argc == 1)
  977.     {
  978.     help();
  979.     return EXIT_SUCCESS;
  980.     }
  981.     else if (argc == 2)
  982.     {
  983.     command = 'L';
  984.     arc_p = argv[1];
  985.     }
  986.     else if (argc >= 3) /*SJD Sat  12-28-1991  14:26:05 */
  987.     {
  988.     if (strlen(argv[1]) > 1)
  989.         error(M_BADCOMND, argv[1]);
  990.     command = toupper(*argv[1]);
  991.     if (strchr("ELTX", command) == NULL)
  992.         error(M_BADCOMND, argv[1]);
  993.     arc_p = argv[2];
  994.  
  995.         list=argv+3;
  996.     }
  997.     else
  998.     {
  999.     help();
  1000.     return EXIT_FAILURE;
  1001.     }
  1002.  
  1003.     strncopy(arc_name, arc_p, FNAME_MAX);
  1004.     case_path(arc_name);
  1005.     i = strlen(arc_name);
  1006.     j = parse_path(arc_name, (char *)NULL, (char *)NULL);
  1007.     lastc = arc_name[i - 1];
  1008.     if (lastc == ARJ_DOT)
  1009.     arc_name[i - 1] = NULL_CHAR;
  1010.     else if (strchr(&arc_name[j], ARJ_DOT) == NULL)
  1011.     strcat(arc_name, M_SUFFIX);
  1012.  
  1013.     make_crctable();
  1014.  
  1015.     error_count = 0;
  1016.     clock_inx = 0;
  1017.     arcfile = NULL;
  1018.     outfile = NULL;
  1019.  
  1020.     execute_cmd(list);
  1021.  
  1022.     if (error_count > 0)
  1023.     error(M_ERRORCNT, "");
  1024.  
  1025.     return EXIT_SUCCESS;
  1026. }
  1027.  
  1028. /* end UNARJ.C */
  1029.