home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unarj.zip / src / unarj.c < prev    next >
C/C++ Source or Header  |  1996-12-04  |  30KB  |  1,271 lines

  1. /* UNARJ.C, UNARJ, R JUNG, 02/17/93
  2.  * Main Extractor routine
  3.  * Copyright (c) 1991-93 by Robert K Jung.  All rights reserved.
  4.  *
  5.  *   This code may be freely used in programs that are NOT ARJ archivers
  6.  *   (both compress and extract ARJ archives).
  7.  *
  8.  *   If you wish to distribute a modified version of this program, you
  9.  *   MUST indicate that it is a modified version both in the program and
  10.  *   source code.
  11.  *
  12.  *   I am holding the copyright on the source code, so please do not
  13.  *   delete my name from the program files or from the 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.  * 06/03/91  R. Jung     Changed arguments in get_mode_str() and
  29.  *                       set_ftime_mode().
  30.  * 06/19/81  R. Jung     Added two more %c in printf() in list_arc().
  31.  * 07/07/91  R. Jung     Added default_case_path() to extract().
  32.  *                       Added strlower().
  33.  * 07/20/91  R. Jung     Changed uint ratio() to static uint ratio().
  34.  * 07/21/91  R. Jung     Added #ifdef VMS.
  35.  * 08/28/91  R. Jung     Changed M_DIFFHOST message.
  36.  * 08/31/91  R. Jung     Added changes to support MAC THINK_C compiler
  37.  *                       per Eric Larson.
  38.  * 10/07/91  R. Jung     Added missing ; to THINK_C additions.
  39.  * 11/11/91  R. Jung     Added host_os test to fwrite_txt_crc().
  40.  * 11/24/91  R. Jung     Added more error_count processing.
  41.  * 12/03/91  R. Jung     Added backup file processing.
  42.  * 02/17/93  R. Jung     Added archive modified date support.
  43.  * 09/02/93  K. Flint    Added wildcards and extraction paths.
  44.  * 01/24/94  K. Flint    Added wildcard expansion to archive file path
  45.  * 16/10/97  Viking      Changed mismatchToolKit & BC for OS/2 v1.0: not _OS2
  46.  *             but __OS2___ :)
  47.  * 16/10/97  Viking      Bug on extract with full pathname corrected.
  48.  *             Sorry for lefty code but I worked with Pascal only ;)
  49.  *
  50.  */
  51.  
  52. #include "unarj.h"
  53.  
  54. #ifdef MODERN
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <ctype.h>
  58. #else /* !MODERN */
  59. extern void free();
  60. extern void exit();
  61. extern char *strcat();
  62. extern char *strcpy();
  63. extern char *strncpy();
  64. extern char *strchr();
  65. extern char *strrchr();
  66. extern int strlen();
  67. extern int strcmp();
  68. #ifdef VMS
  69. #include <ssdef.h>
  70. #define EXIT_FAILURE SS$_ABORT
  71. #define EXIT_SUCCESS SS$_NORMAL
  72. #else
  73. #define EXIT_FAILURE (1)
  74. #define EXIT_SUCCESS (0)
  75. #endif
  76. #define toupper(c)   ((c)>='a'&&(c)<='z'?(c)-('a'-'A'):(c))
  77. #define tolower(c)   ((c)>='A'&&(c)<='Z'?(c)+('a'-'A'):(c))
  78. #endif /* ?MODERN */
  79.  
  80. #ifdef THINK_C
  81. #include <console.h>
  82. #endif
  83.  
  84. #ifdef __OS2__
  85. #define _OS2
  86. #endif
  87.  
  88. /* DosFindFirst() stuff */
  89. #ifdef _OS2
  90. #define INCL_DOSFILEMGR
  91. #include <os2.h>
  92. #define NORMAL_FILES 0L
  93. #endif
  94.  
  95. /* Global variables */
  96.  
  97. UCRC   crc;
  98. FILE   *arcfile;
  99. FILE   *outfile;
  100. ushort bitbuf;
  101. long   compsize;
  102. long   origsize;
  103. uchar  subbitbuf;
  104. uchar  header[HEADERSIZE_MAX];
  105. char   arc_name[FNAME_MAX];
  106. int    command;
  107. int    bitcount;
  108. int    file_type;
  109. int    no_output;
  110. int    error_count;
  111.  
  112. /* Messages */
  113.  
  114. static char *M_USAGE  [] =
  115. {
  116. "Usage: UNARJ <archive>[.arj]    (list archive) or \n",
  117. "       UNARJ <Command> <archive>[.arj] [outpath][fs1] [path][fs2] ...\n",
  118. "       Commands:   E    (extract archive)     L    (list archive)\n",
  119. "                   T    (test archive)        X    (extract with pathnames)\n",
  120. "       outpath: Changes extract path for all files (default = current dir)\n",
  121. "       path: overides outpath for next filespec only\n",
  122. "       fs: filespec - file[s] to extract (wildcards *,? OK)\n",
  123. "\n",
  124. "This is an ARJ demonstration program and ** IS NOT OPTIMIZED ** for speed.\n",
  125. "You may freely use, copy and distribute this program, provided that no fee\n",
  126. "is charged for such use, copying or distribution, and it is distributed\n",
  127. "ONLY in its original unmodified state.  UNARJ is provided as is without\n",
  128. "warranty of any kind, express or implied, including but not limited to\n",
  129. "the implied warranties of merchantability and fitness for a particular\n",
  130. "purpose.  Refer to UNARJ.DOC for more warranty information.\n",
  131. "\n",
  132. "ARJ Software                    Internet address :  robjung@world.std.com\n",
  133. "Robert and Susan Jung           CompuServe userid:  72077,445\n",
  134. "2606 Village Road West\n",
  135. "Norwood, Massachusetts 02062 USA\n",
  136. NULL
  137. };
  138.  
  139. char M_VERSION [] = "UNARJ (Modified Demo version) 2.41.kkf.a Copyright (c) 1991-93 Robert K Jung\nModifed by Kerry Flint\n\n";
  140.  
  141. char M_ARCDATE [] = "Archive created: %s";
  142. char M_ARCDATEM[] = ", modified: %s";
  143. char M_BADCOMND[] = "Bad UNARJ command: %s";
  144. char M_BADCOMNT[] = "Invalid comment header";
  145. char M_BADHEADR[] = "Bad header";
  146. char M_BADTABLE[] = "Bad Huffman code";
  147. char M_CANTOPEN[] = "Can't open %s";
  148. char M_CANTREAD[] = "Can't read file or unexpected end of file";
  149. char M_CANTWRIT[] = "Can't write file. Disk full?";
  150. char M_CRCERROR[] = "CRC error!\n";
  151. char M_CRCOK   [] = "CRC OK\n";
  152. char M_DIFFHOST[] = "  Binary file!";
  153. char M_ENCRYPT [] = "File is password encrypted, ";
  154. char M_ERRORCNT[] = "%sFound %5d error(s)!";
  155. char M_EXTRACT [] = "Extracting %-25s";
  156. char M_FEXISTS [] = "%-25s exists, ";
  157. char M_HEADRCRC[] = "Header CRC error!";
  158. char M_NBRFILES[] = "%5d file(s)\n";
  159. char M_NOMEMORY[] = "Out of memory";
  160. char M_NOTARJ  [] = "%s is not an ARJ archive";
  161. char M_PROCARC [] = "Processing archive: %s\n";
  162. char M_SKIPPED [] = "Skipped %s\n";
  163. char M_SUFFIX  [] = ARJ_SUFFIX;
  164. char M_TESTING [] = "Testing    %-25s";
  165. char M_UNKNMETH[] = "Unsupported method: %d, ";
  166. char M_UNKNTYPE[] = "Unsupported file type: %d, ";
  167. char M_UNKNVERS[] = "Unsupported version: %d, ";
  168.  
  169. #define get_crc()       get_longword()
  170. #define fget_crc(f)     fget_longword(f)
  171.  
  172. #define setup_get(PTR)  (get_ptr = (PTR))
  173. #define get_byte()      ((uchar)(*get_ptr++ & 0xff))
  174.  
  175. #define BUFFERSIZE      4096
  176.  
  177. #define ASCII_MASK      0x7F
  178.  
  179. #define CRCPOLY         0xEDB88320L
  180.  
  181. #define UPDATE_CRC(r,c) r=crctable[((uchar)(r)^(uchar)(c))&0xff]^(r>>CHAR_BIT)
  182.  
  183. /* Local functions */
  184.  
  185. #ifdef MODERN
  186. static void  make_crctable(void);
  187. static void  crc_buf(char *str, int len);
  188. static void  strparity(uchar *p);
  189. static FILE  *fopen_msg(char *name, char *mode);
  190. static int   fget_byte(FILE *f);
  191. static uint  fget_word(FILE *f);
  192. static ulong fget_longword(FILE *f);
  193. static void  fread_crc(uchar *p, int n, FILE *f);
  194. static void  decode_path(char *name);
  195. static void  get_date_str(char *str, ulong tstamp);
  196. static int   parse_path(char *pathname, char *path, char *entry);
  197. #ifdef _OS2
  198. static char* parse_dir(char *fullpathname, char *others); /* by VIC*/
  199. #endif
  200. static void  strncopy(char *to, char *from, int len);
  201. static uint  get_word(void);
  202. static ulong get_longword(void);
  203. static long  find_header(FILE *fd);
  204. static int   read_header(int first, FILE *fd, char *name);
  205. static void  skip(void);
  206. static void  unstore(void);
  207. static int   check_flags(void);
  208. static int   extract(void);
  209. static int   test(void);
  210. static uint  ratio(long a, long b);
  211. static void  list_start(void);
  212. static void  list_arc(int count);
  213. static void  execute_cmd(void);
  214. static void  help(void);
  215. #endif /* MODERN */
  216.  
  217. /* Local variables */
  218.  
  219. static char   filename[FNAME_MAX];
  220. static char   extract_to_dir[FNAME_MAX];
  221. static char   comment[COMMENT_MAX];
  222. static char   *hdr_filename;
  223. static char   *hdr_comment;
  224. static char   **extract_files;
  225. static int    num_extract_files = 0;
  226.  
  227. static ushort headersize;
  228. static uchar  first_hdr_size;
  229. static uchar  arj_nbr;
  230. static uchar  arj_x_nbr;
  231. static uchar  host_os;
  232. static uchar  arj_flags;
  233. static short  method;
  234. static uint   file_mode;
  235. static ulong  time_stamp;
  236. static short  entry_pos;
  237. static ushort host_data;
  238. static uchar  *get_ptr;
  239. static UCRC   file_crc;
  240. static UCRC   header_crc;
  241.  
  242. static long   first_hdr_pos;
  243. static long   torigsize;
  244. static long   tcompsize;
  245.  
  246. static int    clock_inx;
  247.  
  248. static char   *writemode[2]  = { "wb",  "w" };
  249.  
  250. static UCRC   crctable[UCHAR_MAX + 1];
  251.  
  252. /* Functions */
  253.  
  254. static void
  255. make_crctable()
  256. {
  257.     uint i, j;
  258.     UCRC r;
  259.  
  260.     for (i = 0; i <= UCHAR_MAX; i++)
  261.     {
  262.         r = i;
  263.     for (j = CHAR_BIT; j > 0; j--)
  264.         {
  265.         if (r & 1)
  266.                 r = (r >> 1) ^ CRCPOLY;
  267.             else
  268.         r >>= 1;
  269.     }
  270.     crctable[i] = r;
  271.     }
  272. }
  273.  
  274. static void
  275. crc_buf(str, len)
  276. char *str;
  277. int  len;
  278. {
  279.     while (len--)
  280.         UPDATE_CRC(crc, *str++);
  281. }
  282.  
  283. void
  284. disp_clock()
  285. {
  286.     static char clock_str[4] = { '|', '/', '-', '\\' };
  287.  
  288.     printf("(%c)\b\b\b", clock_str[clock_inx]);
  289.     clock_inx = (clock_inx + 1) & 0x03;
  290. }
  291.  
  292. void
  293. error(fmt, arg)
  294. char *fmt;
  295. char *arg;
  296. {
  297.     putc('\n', stdout);
  298.     printf(fmt, arg, error_count);
  299.     putc('\n', stdout);
  300.     exit(EXIT_FAILURE);
  301. }
  302.  
  303. static void
  304. strparity(p)
  305. uchar *p;
  306. {
  307.     while (*p)
  308.     {
  309.         FIX_PARITY(*p);
  310.         p++;
  311.     }
  312. }
  313.  
  314. static FILE *
  315. fopen_msg(name, mode)
  316. char *name;
  317. char *mode;
  318. {
  319.     FILE *fd;
  320.  
  321.     fd = file_open(name, mode);
  322.     if (fd == NULL)
  323.     error(M_CANTOPEN, name);
  324.     return fd;
  325. }
  326.  
  327. static int
  328. fget_byte(f)
  329. FILE *f;
  330. {
  331.     int c;
  332.  
  333.     if ((c = getc(f)) == EOF)
  334.     error(M_CANTREAD, "");
  335.     return c & 0xFF;
  336. }
  337.  
  338. static uint
  339. fget_word(f)
  340. FILE *f;
  341. {
  342.     uint b0, b1;
  343.  
  344.     b0 = fget_byte(f);
  345.     b1 = fget_byte(f);
  346.     return (b1 << 8) + b0;
  347. }
  348.  
  349. static ulong
  350. fget_longword(f)
  351. FILE *f;
  352. {
  353.     ulong b0, b1, b2, b3;
  354.  
  355.     b0 = fget_byte(f);
  356.     b1 = fget_byte(f);
  357.     b2 = fget_byte(f);
  358.     b3 = fget_byte(f);
  359.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  360. }
  361.  
  362. static void
  363. fread_crc(p, n, f)
  364. uchar *p;
  365. int   n;
  366. FILE  *f;
  367. {
  368.     n = file_read((char *)p, 1, n, f);
  369.     origsize += n;
  370.     crc_buf((char *)p, n);
  371. }
  372.  
  373. void
  374. fwrite_txt_crc(p, n)
  375. uchar *p;
  376. int   n;
  377. {
  378.     uchar c;
  379.  
  380.     crc_buf((char *)p, n);
  381.     if (no_output)
  382.     return;
  383.  
  384.     if (file_type == TEXT_TYPE)
  385.     {
  386.     while (n--)
  387.         {
  388.             c = *p++;
  389.             if (host_os != OS)
  390.         {
  391.         FIX_PARITY(c);
  392.             }
  393.         if (putc((int) c, outfile) == EOF)
  394.                 error(M_CANTWRIT, "");
  395.     }
  396.     }
  397.     else
  398.     {
  399.     if (file_write((char *)p, 1, n, outfile) != n)
  400.             error(M_CANTWRIT, "");
  401.     }
  402. }
  403.  
  404. void
  405. init_getbits()
  406. {
  407.     bitbuf = 0;
  408.     subbitbuf = 0;
  409.     bitcount = 0;
  410.     fillbuf(2 * CHAR_BIT);
  411. }
  412.  
  413. void
  414. fillbuf(n)                /* Shift bitbuf n bits left, read n bits */
  415. int n;
  416. {
  417.     bitbuf = (bitbuf << n) & 0xFFFF;  /* lose the first n bits */
  418.     while (n > bitcount)
  419.     {
  420.     bitbuf |= subbitbuf << (n -= bitcount);
  421.     if (compsize != 0)
  422.         {
  423.         compsize--;
  424.         subbitbuf = (uchar) getc(arcfile);
  425.     }
  426.         else
  427.             subbitbuf = 0;
  428.     bitcount = CHAR_BIT;
  429.     }
  430.     bitbuf |= subbitbuf >> (bitcount -= n);
  431. }
  432.  
  433. ushort
  434. getbits(n)
  435. int n;
  436. {
  437.     ushort x;
  438.  
  439.     x = bitbuf >> (2 * CHAR_BIT - n);
  440.     fillbuf(n);
  441.     return x;
  442. }
  443.  
  444. static void
  445. decode_path(name)
  446. char *name;
  447. {
  448.     for ( ; *name; name++)
  449.     {
  450.     if (*name == ARJ_PATH_CHAR)
  451.         *name = PATH_CHAR;
  452.     }
  453. }
  454.  
  455. static void
  456. get_date_str(str, tstamp)
  457. char  *str;
  458. ulong tstamp;
  459. {
  460.     sprintf(str, "%04u-%02u-%02u %02u:%02u:%02u",
  461.        ts_year(tstamp), ts_month(tstamp), ts_day(tstamp),
  462.        ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
  463. }
  464.  
  465. static int
  466. parse_path(pathname, path, entry)
  467. char *pathname;
  468. char *path;
  469. char *entry;
  470. {
  471.     char *cptr, *ptr, *fptr;
  472.     short pos;
  473.  
  474.     fptr = NULL;
  475.     for (cptr = PATH_SEPARATORS; *cptr; cptr++)
  476.     {
  477.     if ((ptr = strrchr(pathname, *cptr)) != NULL &&
  478.         (fptr == NULL || ptr > fptr))
  479.         fptr = ptr;
  480.     }
  481.     if (fptr == NULL)
  482.     pos = 0;
  483.     else
  484.     pos = fptr + 1 - pathname;
  485.     if (path != NULL)
  486.     {
  487.        strncpy(path, pathname, pos);
  488.        path[pos] = NULL_CHAR;
  489.     }
  490.     if (entry != NULL)
  491.        strcpy(entry, &pathname[pos]);
  492.     return pos;
  493. }
  494.  
  495.  
  496. static void
  497. strncopy(to, from, len)
  498. char *to;
  499. char *from;
  500. int  len;
  501. {
  502.     int i;
  503.  
  504.     for (i = 1; i < len && *from; i++)
  505.     *to++ = *from++;
  506.     *to = NULL_CHAR;
  507. }
  508.  
  509. void
  510. strlower(s)
  511. char *s;
  512. {
  513.     while (*s)
  514.     {
  515.     *s = (char) tolower(*s);
  516.     s++;
  517.     }
  518. }
  519.  
  520. void
  521. strupper(s)
  522. char *s;
  523. {
  524.     while (*s)
  525.     {
  526.     *s = (char) toupper(*s);
  527.     s++;
  528.     }
  529. }
  530.  
  531. voidp *
  532. malloc_msg(size)
  533. int size;
  534. {
  535.     char *p;
  536.  
  537.     if ((p = (char *)xmalloc(size)) == NULL)
  538.     error(M_NOMEMORY, "");
  539.     return (voidp *)p;
  540. }
  541.  
  542. static uint
  543. get_word()
  544. {
  545.     uint b0, b1;
  546.  
  547.     b0 = get_byte();
  548.     b1 = get_byte();
  549.     return (b1 << 8) + b0;
  550. }
  551.  
  552. static ulong
  553. get_longword()
  554. {
  555.     ulong b0, b1, b2, b3;
  556.  
  557.     b0 = get_byte();
  558.     b1 = get_byte();
  559.     b2 = get_byte();
  560.     b3 = get_byte();
  561.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  562. }
  563.  
  564. static long
  565. find_header(fd)
  566. FILE *fd;
  567. {
  568.     long arcpos, lastpos;
  569.     int c;
  570.  
  571.     arcpos = file_tell(fd);
  572.     file_seek(fd, 0L, SEEK_END);
  573.     lastpos = file_tell(fd) - 2;
  574.     if (lastpos > MAXSFX)
  575.     lastpos = MAXSFX;
  576.     for ( ; arcpos < lastpos; arcpos++)
  577.     {
  578.     file_seek(fd, arcpos, SEEK_SET);
  579.     c = fget_byte(fd);
  580.     while (arcpos < lastpos)
  581.     {
  582.         if (c != HEADER_ID_LO)  /* low order first */
  583.         c = fget_byte(fd);
  584.         else if ((c = fget_byte(fd)) == HEADER_ID_HI)
  585.         break;
  586.         arcpos++;
  587.     }
  588.     if (arcpos >= lastpos)
  589.         break;
  590.     if ((headersize = fget_word(fd)) <= HEADERSIZE_MAX)
  591.     {
  592.         crc = CRC_MASK;
  593.         fread_crc(header, (int) headersize, fd);
  594.         if ((crc ^ CRC_MASK) == fget_crc(fd))
  595.         {
  596.         file_seek(fd, arcpos, SEEK_SET);
  597.         return arcpos;
  598.         }
  599.     }
  600.     }
  601.     return -1;          /* could not find a valid header */
  602. }
  603.  
  604. static int
  605. read_header(first, fd, name)
  606. int  first;
  607. FILE *fd;
  608. char *name;
  609. {
  610.     ushort extheadersize, header_id;
  611.  
  612.     header_id = fget_word(fd);
  613.     if (header_id != HEADER_ID)
  614.     {
  615.     if (first)
  616.         error(M_NOTARJ, name);
  617.     else
  618.         error(M_BADHEADR, "");
  619.     }
  620.  
  621.     headersize = fget_word(fd);
  622.     if (headersize == 0)
  623.     return 0;               /* end of archive */
  624.     if (headersize > HEADERSIZE_MAX)
  625.     error(M_BADHEADR, "");
  626.  
  627.     crc = CRC_MASK;
  628.     fread_crc(header, (int) headersize, fd);
  629.     header_crc = fget_crc(fd);
  630.     if ((crc ^ CRC_MASK) != header_crc)
  631.     error(M_HEADRCRC, "");
  632.  
  633.     setup_get(header);
  634.     first_hdr_size = get_byte();
  635.     arj_nbr = get_byte();
  636.     arj_x_nbr = get_byte();
  637.     host_os = get_byte();
  638.     arj_flags = get_byte();
  639.     method = get_byte();
  640.     file_type = get_byte();
  641.     (void)get_byte();
  642.     time_stamp = get_longword();
  643.     compsize = get_longword();
  644.     origsize = get_longword();
  645.     file_crc = get_crc();
  646.     entry_pos = get_word();
  647.     file_mode = get_word();
  648.     host_data = get_word();
  649.  
  650.     hdr_filename = (char *)&header[first_hdr_size];
  651.     strncopy(filename, hdr_filename, sizeof(filename));
  652.     if (host_os != OS)
  653.     strparity((uchar *)filename);
  654.     if ((arj_flags & PATHSYM_FLAG) != 0)
  655.     decode_path(filename);
  656.  
  657.     hdr_comment = (char *)&header[first_hdr_size + strlen(hdr_filename) + 1];
  658.     strncopy(comment, hdr_comment, sizeof(comment));
  659.     if (host_os != OS)
  660.     strparity((uchar *)comment);
  661.  
  662.     /* if extheadersize == 0 then no CRC */
  663.     /* otherwise read extheader data and read 4 bytes for CRC */
  664.  
  665.     while ((extheadersize = fget_word(fd)) != 0)
  666.     file_seek(fd, (long) (extheadersize + 4), SEEK_CUR);
  667.  
  668.     return 1;                   /* success */
  669. }
  670.  
  671. static void
  672. skip()
  673. {
  674.     file_seek(arcfile, compsize, SEEK_CUR);
  675. }
  676.  
  677. static void
  678. unstore()
  679. {
  680.     int n;
  681.     long pos;
  682.     char *buffer;
  683.  
  684.     buffer = (char *)malloc_msg(BUFFERSIZE);
  685.     pos = file_tell(arcfile);
  686.     disp_clock();
  687.     n = (int)(BUFFERSIZE - (pos % BUFFERSIZE));
  688.     n = compsize > (long)n ? n : (int)compsize;
  689.     while (compsize > 0)
  690.     {
  691.         if (file_read(buffer, 1, n, arcfile) != n)
  692.         error(M_CANTREAD, "");
  693.     disp_clock();
  694.     compsize -= n;
  695.     fwrite_txt_crc((uchar *)buffer, n);
  696.     n = compsize > BUFFERSIZE ? BUFFERSIZE : (int)compsize;
  697.     }
  698.     free(buffer);
  699. }
  700.  
  701. static int
  702. check_flags()
  703. {
  704.     if (arj_x_nbr > ARJ_X_VERSION)
  705.     {
  706.     printf(M_UNKNVERS, arj_x_nbr);
  707.         printf(M_SKIPPED, filename);
  708.     skip();
  709.     return -1;
  710.     }
  711.     if ((arj_flags & GARBLE_FLAG) != 0)
  712.     {
  713.     printf(M_ENCRYPT);
  714.     printf(M_SKIPPED, filename);
  715.     skip();
  716.     return -1;
  717.     }
  718.     if (method < 0 || method > MAXMETHOD || (method == 4 && arj_nbr == 1))
  719.     {
  720.         printf(M_UNKNMETH, method);
  721.     printf(M_SKIPPED, filename);
  722.     skip();
  723.         return -1;
  724.     }
  725.     if (file_type != BINARY_TYPE && file_type != TEXT_TYPE)
  726.     {
  727.         printf(M_UNKNTYPE, file_type);
  728.     printf(M_SKIPPED, filename);
  729.     skip();
  730.     return -1;
  731.     }
  732.     return 0;
  733. }
  734.  
  735. char myupper(char c){
  736.    return(toupper(c));
  737. }
  738.  
  739. static int check_wild(char *wild, char *check){
  740. /* compare a wildcard string with another string */
  741.  
  742.    char *tmp;
  743.  
  744.    tmp = strrchr(wild, '\\'); /* split off path */
  745.    if (tmp)
  746.       wild = tmp + 1;
  747.  
  748.    if (command == 'D')   printf("Comparing %s and %s : ", wild, check);
  749.    while ( ((myupper(*wild) == myupper(*check) ) || *wild == '*' || *wild == '?') && *wild) {
  750.       if (myupper(*wild) == myupper(*check)) {
  751.      wild++;
  752.      check++;
  753.       } else { /* wild card */
  754.      if (*wild == '?') { /* match any single char */
  755.             if (*check != '.' && *check ){ /* don't increment if next char . or \0 */
  756.            check++;
  757.         }
  758.         wild++;
  759.      } else { /* * match any number of characters */
  760.         while (*wild == '*' || *wild == '?') { /* skip to next non wild */
  761.            wild++;
  762.             } /* endwhile */
  763.         if (!*wild) { /* matches to EOS */
  764.            while (*check) {
  765.           check++;
  766.            } /* endwhile */
  767.             } else {
  768.                tmp = check;
  769.            while (*tmp) { /* find last char that matches */
  770.           if (myupper(*tmp) == myupper(*wild)){
  771.              check = tmp;
  772.           }
  773.           tmp++;
  774.            }
  775.            if (*wild == '.' && *check != '.'){ /* make EOS dot pos */
  776.           check = tmp;
  777.           wild++;
  778.         }
  779.         } /* endif */
  780.          } /* endif */
  781.       } /* endif */
  782.    } /* endwhile */
  783.    if (*wild == *check) {
  784.        if (command == 'D')      printf("Match\n");
  785.       return(1);
  786.    } else {
  787.       if (command == 'D')      printf("No-Wild=%s & Check =%s\n", wild, check);
  788.       return(0);
  789.    } /* endif */
  790. }
  791.  
  792. static int file_check(char *name){
  793.  
  794.    int i, len, n_len, e_len;
  795.    char *ext;
  796.  
  797.    if (!num_extract_files) {
  798.       return(1);
  799.    } /* endif */
  800.    for (i=0;i < num_extract_files; i++ ) {
  801. #ifdef SIMPLE_WILDS
  802.       /* exact match */
  803.       if (stricmp(name, extract_files[i]) == 0)
  804.      return(1);
  805.       /* Every file wild card */
  806.       if (strcmp("*.*", extract_files[i]) == 0 ||
  807.       strcmp("*", extract_files[i]) == 0) {
  808.      return(1);
  809.       } /* endif */
  810.       /* check just extensions */
  811.       if (strncmp("*.", extract_files[i], 2) == 0) {
  812.      ext = strrchr(name, '.');
  813.      if (ext){
  814.         if (stricmp(ext, &extract_files[i][2]) == 0){
  815.            return (1);
  816.         }
  817.      }
  818.       } else {
  819.      /* any extension */
  820.      len = strlen(extract_files[i]);
  821.      if (strcmp(".*", &extract_files[i][len -2]) == 0){
  822.         ext = strrchr(name, '.');
  823.         if (ext) {
  824.            e_len = strlen(ext);
  825.         } else {
  826.            e_len = 0;
  827.         } /* endif */
  828.         n_len = strlen(name) - e_len;
  829.         if (strnicmp(name, extract_files[i], len-2) == 0 && (n_len == len - 2)){
  830.            return(1);
  831.         }
  832.      }
  833.       } /* endif */
  834. #else
  835.       if (check_wild(extract_files[i], name)){
  836.      strcpy(extract_to_dir, extract_files[i]); /* figure out which extract path to use */
  837.      ext = strrchr(extract_to_dir, '\\');
  838.      if (ext) {
  839.         *(ext+1) = '\0';
  840.      } else {
  841.         strcpy(extract_to_dir, extract_files[0]);
  842.         ext = strrchr(extract_to_dir, '\\');
  843.         if (ext) {
  844.            *(ext+1) = '\0';
  845.         } else {
  846.            strcpy(extract_to_dir, DEFAULT_DIR);
  847.         }
  848.      } /* endif */
  849.      return(1);
  850.       }
  851. #endif
  852.    } /* endfor */
  853.    return(0);
  854. }
  855.  
  856. #ifdef _OS2
  857. static char* parse_dir(char *fullpathname, char *others)
  858. {
  859.     char *cptr, *fptr;
  860.     char *firstdir;
  861.     char ppp[FNAME_MAX];
  862.     short pos;
  863.  
  864.     firstdir = "";
  865.     cptr = "";
  866.     strcpy(ppp,PATH_SEPARATORS);
  867.  
  868. /*    for (pos = 1; strlen(PATH_SEPARATORS); pos++) */
  869.     for (cptr = PATH_SEPARATORS; *cptr; cptr++)
  870.     {
  871.     if (strpbrk(fullpathname, cptr) != NULL) {
  872.          fptr = cptr;
  873.          strncpy(firstdir, fullpathname, strcspn(fullpathname, ppp));
  874.          cptr = fptr;
  875.          }
  876.     else firstdir="";
  877.     }
  878.     if (firstdir=="") {
  879.     others = "";
  880.     pos=0;
  881.     }
  882.     else {
  883.     pos=strlen(firstdir)+1;
  884.     others = "";
  885.     fptr = (char *)&fullpathname[pos];
  886.     strcpy(others, fptr);
  887.     }
  888.     return firstdir;
  889. }
  890. #endif
  891.  
  892. static int
  893. extract()
  894. {
  895.     char name[FNAME_MAX];
  896. /* VIC002: */
  897.     char path_of_file[FNAME_MAX];
  898.     char path[FNAME_MAX];
  899.     char entry[FNAME_MAX];
  900. /*    char pathtocreate[FNAME_MAX]; */
  901.     char *otherpath;
  902.     char *makedpath;
  903.     char *currentpath;
  904.     char *p;
  905.     APIRET rc;
  906.  
  907.     if (check_flags())
  908.     {
  909.     error_count++;
  910.     return 0;
  911.     }
  912.  
  913.     no_output = 0;
  914.     if (command == 'E'){
  915.     strcpy(name, extract_to_dir);
  916.     strcat(name, &filename[entry_pos]);
  917.     } else
  918.     {
  919.     strcpy(name, extract_to_dir);
  920.     strcat(name, filename);
  921.     }
  922.  
  923.     if (host_os != OS)
  924.     default_case_path(name);
  925.  
  926. /* modified by Viking */
  927. #ifdef _OS2
  928. makedpath = "";
  929. currentpath = "";
  930. parse_path(name, path, entry);
  931. p = parse_dir(name, otherpath);
  932. while (otherpath != "")
  933. {
  934. printf("Making dir %s...\n",p);
  935. strcat(makedpath,p);
  936. /*rc=DosCreateDir(makedpath,NULL);
  937. if (rc != 0)
  938.   printf("Error create dir!");*/
  939. strcat(makedpath,"\\");
  940. strcpy(currentpath, otherpath);
  941. p = parse_dir(currentpath, otherpath);
  942. strcpy(currentpath,otherpath);
  943. }
  944. printf(otherpath,"\n");
  945. #endif
  946.  
  947.     if (file_exists(name))
  948.     {
  949.     printf(M_FEXISTS, name);
  950.     printf(M_SKIPPED, name);
  951.     skip();
  952.     error_count++;
  953.     return 0;
  954.     }
  955.     outfile = file_open(name, writemode[file_type & 1]);
  956.     if (outfile == NULL)
  957.     {
  958.     printf(M_CANTOPEN, name);
  959.     putchar('\n');
  960.     skip();
  961.     error_count++;
  962.     return 0;
  963.     }
  964.     printf(M_EXTRACT, name);
  965.     if (host_os != OS && file_type == BINARY_TYPE)
  966.     printf(M_DIFFHOST);
  967.     printf("  ");
  968.  
  969.     crc = CRC_MASK;
  970.  
  971.     if (method == 0)
  972.         unstore();
  973.     else if (method == 1 || method == 2 || method == 3)
  974.     decode();
  975.     else if (method == 4)
  976.     decode_f();
  977.     fclose(outfile);
  978.  
  979.     set_ftime_mode(name, time_stamp, file_mode, (uint) host_os);
  980.  
  981.     if ((crc ^ CRC_MASK) == file_crc)
  982.     printf(M_CRCOK);
  983.     else
  984.     {
  985.     printf(M_CRCERROR);
  986.         error_count++;
  987.     }
  988.     return 1;
  989. }
  990.  
  991. static int
  992. test()
  993. {
  994.     if (check_flags())
  995.     return 0;
  996.  
  997.     no_output = 1;
  998.     printf(M_TESTING, filename);
  999.     printf("  ");
  1000.  
  1001.     crc = CRC_MASK;
  1002.  
  1003.     if (method == 0)
  1004.     unstore();
  1005.     else if (method == 1 || method == 2 || method == 3)
  1006.     decode();
  1007.     else if (method == 4)
  1008.         decode_f();
  1009.  
  1010.     if ((crc ^ CRC_MASK) == file_crc)
  1011.     printf(M_CRCOK);
  1012.     else
  1013.     {
  1014.     printf(M_CRCERROR);
  1015.         error_count++;
  1016.     }
  1017.     return 1;
  1018. }
  1019.  
  1020. static uint
  1021. ratio(a, b)
  1022. long a, b;
  1023. {
  1024.    int i;
  1025.  
  1026.    for (i = 0; i < 3; i++)
  1027.        if (a <= LONG_MAX / 10)
  1028.            a *= 10;
  1029.        else
  1030.        b /= 10;
  1031.    if ((long) (a + (b >> 1)) < a)
  1032.    {
  1033.        a >>= 1;
  1034.        b >>= 1;
  1035.    }
  1036.    if (b == 0)
  1037.        return 0;
  1038.    return (uint) ((a + (b >> 1)) / b);
  1039. }
  1040.  
  1041. static void
  1042. list_start()
  1043. {
  1044.     printf("Filename       Original Compressed Ratio DateTime modified CRC-32   AttrBTPMGVX\n");
  1045.     printf("------------ ---------- ---------- ----- ----------------- -------- -----------\n");
  1046. }
  1047.  
  1048. static void
  1049. list_arc(count)
  1050. int count;
  1051. {
  1052.     uint r;
  1053.     int garble_mode, path_mode, volume_mode, extfil_mode, ftype, bckf_mode;
  1054.     char date_str[20], fmode_str[10];
  1055.     static char mode[5] = { 'B', 'T', '?', 'D', 'V' };
  1056.     static char pthf[2] = { ' ', '+' };
  1057.     static char pwdf[2] = { ' ', 'G' };  /* plain, encrypted */
  1058.     static char volf[2] = { ' ', 'V' };
  1059.     static char extf[2] = { ' ', 'X' };
  1060.     static char bckf[2] = { ' ', '*' };
  1061.  
  1062.     if (count == 0)
  1063.     list_start();
  1064.  
  1065.     garble_mode = ((arj_flags & GARBLE_FLAG) != 0);
  1066.     volume_mode = ((arj_flags & VOLUME_FLAG) != 0);
  1067.     extfil_mode = ((arj_flags & EXTFILE_FLAG) != 0);
  1068.     bckf_mode   = ((arj_flags & BACKUP_FLAG) != 0);
  1069.     path_mode   = (entry_pos > 0);
  1070.     r = ratio(compsize, origsize);
  1071.     torigsize += origsize;
  1072.     tcompsize += compsize;
  1073.     ftype = file_type;
  1074.     if (ftype != BINARY_TYPE && ftype != TEXT_TYPE && ftype != DIR_TYPE &&
  1075.         ftype != LABEL_TYPE)
  1076.         ftype = 3;
  1077.     get_date_str(date_str, time_stamp);
  1078.     strcpy(fmode_str, "    ");
  1079.     if (host_os == OS)
  1080.         get_mode_str(fmode_str, (uint) file_mode);
  1081.     if (strlen(&filename[entry_pos]) > 12)
  1082.     printf("%-12s\n             ", &filename[entry_pos]);
  1083.     else
  1084.         printf("%-12s ", &filename[entry_pos]);
  1085.     printf("%10ld %10ld %u.%03u %s %08lX %4s%c%c%c%u%c%c%c\n",
  1086.         origsize, compsize, r / 1000, r % 1000, &date_str[2], file_crc,
  1087.         fmode_str, bckf[bckf_mode], mode[ftype], pthf[path_mode], method,
  1088.         pwdf[garble_mode], volf[volume_mode], extf[extfil_mode]);
  1089. }
  1090.  
  1091. static void
  1092. execute_cmd()
  1093. {
  1094.     int file_count;
  1095.     char date_str[22];
  1096.     uint r;
  1097.     int doit;
  1098.    #ifdef _OS2
  1099.    HDIR FindHandle;
  1100.    FILEFINDBUF3 FindBuffer;
  1101.    ULONG FindCount, File_Attribute;
  1102.    APIRET rc;
  1103.    char FileSpec[FNAME_MAX];
  1104.    char PathSpec[FNAME_MAX];
  1105.  
  1106.    FindHandle = 0x0001;
  1107.    FindCount = 1;
  1108.    File_Attribute = NORMAL_FILES | FILE_ARCHIVED | FILE_HIDDEN | FILE_READONLY;  /* All files, no dirs */
  1109.  
  1110.    strncopy(FileSpec, arc_name, FNAME_MAX);
  1111.    parse_path(FileSpec, PathSpec, NULL);
  1112.    rc = DosFindFirst(FileSpec, &FindHandle, File_Attribute, (PVOID) &FindBuffer,
  1113.              sizeof(FindBuffer), &FindCount, FIL_STANDARD);
  1114.    if (rc != 0)
  1115.     error(M_CANTOPEN, arc_name);
  1116.    while (rc == 0) {
  1117. /* VIC001:     strncopy(arc_name, PathSpec, FNAME_MAX); */
  1118.       strncopy(arc_name, FileSpec, FNAME_MAX);
  1119.       strncat(arc_name, FindBuffer.achName, FNAME_MAX - strlen(FileSpec) - 1);
  1120.       /*arc_name[FNAME_MAX -1] = '\0';*/
  1121.       arc_name[strlen(FileSpec)]='\0';
  1122.    #endif
  1123.       first_hdr_pos = 0;
  1124.       time_stamp = 0;
  1125.       first_hdr_size = FIRST_HDR_SIZE;
  1126.  
  1127.       arcfile = fopen_msg(arc_name, "rb");
  1128.  
  1129.       printf(M_PROCARC, arc_name);
  1130.  
  1131.       first_hdr_pos = find_header(arcfile);
  1132.       if (first_hdr_pos < 0)
  1133.      error(M_NOTARJ, arc_name);
  1134.       file_seek(arcfile, first_hdr_pos, SEEK_SET);
  1135.       if (!read_header(1, arcfile, arc_name))
  1136.       error(M_BADCOMNT, "");
  1137.       get_date_str(date_str, time_stamp);
  1138.       printf(M_ARCDATE, date_str);
  1139.       if (arj_nbr >= ARJ_M_VERSION)
  1140.       {
  1141.      get_date_str(date_str, (ulong) compsize);
  1142.      printf(M_ARCDATEM, date_str);
  1143.       }
  1144.       printf("\n");
  1145.  
  1146.       file_count = 0;
  1147.       while (read_header(0, arcfile, arc_name))
  1148.       {
  1149.      strcpy(extract_to_dir, DEFAULT_DIR);
  1150.      doit = file_check(filename+entry_pos);
  1151.      if (!doit)
  1152.         skip();
  1153.      else switch (command)
  1154.      {
  1155.      case 'E':
  1156.      case 'X':
  1157.         if (extract())
  1158.         file_count++;
  1159.         break;
  1160.      case 'L':
  1161.         list_arc(file_count++);
  1162.         skip();
  1163.         break;
  1164.      case 'T':
  1165.         if (test())
  1166.         file_count++;
  1167.         break;
  1168.      case 'D': /* Debug Wildcards only */
  1169.         skip();
  1170.         file_count++;
  1171.         break;
  1172.      }
  1173.       }
  1174.  
  1175.       if (command == 'L')
  1176.       {
  1177.      printf("------------ ---------- ---------- ----- -----------------\n");
  1178.      r = ratio(tcompsize, torigsize);
  1179.      printf(" %5d files %10ld %10ld %u.%03u %s\n",
  1180.         file_count, torigsize, tcompsize, r / 1000, r % 1000, &date_str[2]);
  1181.       }
  1182.       else
  1183.      printf(M_NBRFILES, file_count);
  1184.  
  1185.       fclose(arcfile);
  1186.    #ifdef _OS2
  1187.       rc = DosFindNext(FindHandle, (PVOID) &FindBuffer, sizeof(FindBuffer), &FindCount);
  1188.    } /* endwhile */
  1189.    rc = DosFindClose(FindHandle);
  1190.    #endif
  1191. }
  1192.  
  1193. static void
  1194. help()
  1195. {
  1196.     int i;
  1197.  
  1198.     for (i = 0; M_USAGE[i] != NULL; i++)
  1199.     printf(M_USAGE[i]);
  1200. }
  1201.  
  1202. int
  1203. main(argc, argv)
  1204. int  argc;
  1205. char *argv[];
  1206. {
  1207.     int i, j, lastc;
  1208.     char *arc_p;
  1209.  
  1210. #ifdef THINK_C
  1211.     argc = ccommand(&argv);
  1212. #endif
  1213. #ifdef __IBMC__
  1214.     setvbuf(stdout, NULL, _IONBF, 0L);
  1215. #endif
  1216.     printf(M_VERSION);
  1217.  
  1218.     if (argc == 1)
  1219.     {
  1220.         help();
  1221.     return EXIT_SUCCESS;
  1222.     }
  1223.     else if (argc == 2)
  1224.     {
  1225.         command = 'L';
  1226.         arc_p = argv[1];
  1227.     }
  1228.     else if (argc >= 3)
  1229.     {
  1230.     if (strlen(argv[1]) > 1)
  1231.             error(M_BADCOMND, argv[1]);
  1232.     command = toupper(*argv[1]);
  1233.     if (strchr("ELTXD", command) == NULL)
  1234.         error(M_BADCOMND, argv[1]);
  1235.     arc_p = argv[2];
  1236.     extract_files = &argv[3];
  1237.     num_extract_files = argc - 3;
  1238.     }
  1239.     else
  1240.     {
  1241.     help();
  1242.     return EXIT_FAILURE;
  1243.     }
  1244.  
  1245.     strncopy(arc_name, arc_p, FNAME_MAX);
  1246.     case_path(arc_name);
  1247.     i = strlen(arc_name);
  1248.     j = parse_path(arc_name, (char *)NULL, (char *)NULL);
  1249.     lastc = arc_name[i - 1];
  1250.     if (lastc == ARJ_DOT)
  1251.     arc_name[i - 1] = NULL_CHAR;
  1252.     else if (strchr(&arc_name[j], ARJ_DOT) == NULL)
  1253.     strcat(arc_name, M_SUFFIX);
  1254.  
  1255.     make_crctable();
  1256.  
  1257.     error_count = 0;
  1258.     clock_inx = 0;
  1259.     arcfile = NULL;
  1260.     outfile = NULL;
  1261.  
  1262.     execute_cmd();
  1263.  
  1264.     if (error_count > 0)
  1265.     error(M_ERRORCNT, "");
  1266.  
  1267.     return EXIT_SUCCESS;
  1268. }
  1269.  
  1270. /* end UNARJ.C */
  1271.