"Fossies" - the Fresh Open Source Software Archive

Member "unarj-2.65/unarj.c" (5 Jun 2002, 23208 Bytes) of package /linux/misc/old/unarj-2.65.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "unarj.c" see the Fossies "Dox" file reference documentation.

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