home *** CD-ROM | disk | FTP | other *** search
/ The Original Shareware 1992 / TheOrigSharewareV1.cdr / 25 / arj200.exe / arj / UNARJ.ARJ / UNARJ.C < prev    next >
C/C++ Source or Header  |  1991-04-05  |  14KB  |  678 lines

  1. /* UNARJ.C, UNARJ, R JUNG, 04/05/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. /* Modification history:
  8. /* Date      Programmer  Description of modification.
  9. /* 04/05/91  R. Jung     Rewrote code.
  10. /*
  11.  */
  12.  
  13. #include "unarj.h"
  14.  
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. /* Global variables */
  21.  
  22. UCRC   crc;
  23. FILE   *arcfile;
  24. FILE   *outfile;
  25. ushort bitbuf;
  26. long   compsize;
  27. long   origsize;
  28. uchar  subbitbuf;
  29. uchar  header[HEADERSIZE_MAX];
  30. char   arc_name[FNAME_MAX];
  31. int    bitcount;
  32. int    file_type;
  33. int    error_count;
  34.  
  35. /* Messages */
  36.  
  37. char M_VERSION [] = "UNARJ 2.00 Copyright (c) 1991 Robert K Jung\n\n";
  38. char M_USAGE   [] = "Usage:  UNARJ archive[.arj] [NUL]\n";
  39.  
  40. char M_ARCDATE [] = "Archive date      : %s\n";
  41. char M_BADCOMNT[] = "Invalid comment header";
  42. char M_BADHEADR[] = "Bad header";
  43. char M_BADTABLE[] = "Bad Huffman code (%d)";
  44. char M_CANTOPEN[] = "Can't open %s";
  45. char M_CANTREAD[] = "Can't read file or unexpected end of file";
  46. char M_CANTWRIT[] = "Can't write file. Disk full?";
  47. char M_CRCERROR[] = "CRC error!\n";
  48. char M_CRCOK   [] = "CRC OK\n";
  49. char M_DIFFHOST[] = ", Warning! Binary file from a different OS";
  50. char M_DIR     [] = "directory ";
  51. char M_ENCRYPT [] = "File is password encrypted, ";
  52. char M_ERRORCNT[] = "Found %5d error(s)!";
  53. char M_EXTRACT [] = "Extracting %-12s";
  54. char M_FEXISTS [] = "%-12s exists, ";
  55. char M_HEADRCRC[] = "Header CRC error!";
  56. char M_NBRFILES[] = "%5d file(s)\n";
  57. char M_NOMEMORY[] = "Out of memory";
  58. char M_NOTARJ  [] = "%s is not an ARJ archive";
  59. char M_PROCARC [] = "Processing archive: %s\n";
  60. char M_SKIPPED [] = "Skipped %s\n";
  61. char M_SUFFIX  [] = ARJ_SUFFIX;
  62. char M_TESTING [] = "Testing    %-12s";
  63. char M_UNKNMETH[] = "Unknown method: %d, ";
  64. char M_UNKNTYPE[] = "Unknown file type: %d, ";
  65. char M_UNKNVERS[] = "Unknown version: %d, ";
  66. char M_UNSTORE [] = "Unstoring         ";
  67.  
  68. #define get_crc()    get_longword()
  69. #define fget_crc(f)    fget_longword(f)
  70.  
  71. #define setup_get(PTR)    (get_ptr = (PTR))
  72. #define get_byte()      ((uchar)(*get_ptr++ & 0xff))
  73.  
  74. #define BUFFERSIZE      4096
  75.  
  76. #define ASCII_MASK      0x7F
  77.  
  78. #define CRCPOLY         0xEDB88320UL
  79.  
  80. #if CHAR_BIT == 8
  81. #define UPDATE_CRC(crc, c)  \
  82.         crc = crctable[(uchar)crc ^ (uchar)(c)] ^ (crc >> CHAR_BIT)
  83. #else
  84. #define UPDATE_CRC(crc, c)  \
  85.         crc = crctable[((uchar)(crc) ^ (uchar)(c)) & 0xFF] ^ (crc >> CHAR_BIT)
  86. #endif
  87.  
  88. /* Local variables */
  89.  
  90. static char   filename[FNAME_MAX];
  91. static char   comment[COMMENT_MAX];
  92. static char   *hdr_filename;
  93. static char   *hdr_comment;
  94.  
  95. static ushort headersize;
  96. static uchar  first_hdr_size;
  97. static uchar  arj_nbr;
  98. static uchar  arj_x_nbr;
  99. static uchar  host_os;
  100. static uchar  arj_flags;
  101. static short  method;
  102. static ushort file_mode;
  103. static ulong  time_stamp;
  104. static short  entry_pos;
  105. static ushort host_data;
  106. static uchar  *get_ptr;
  107. static UCRC   file_crc;
  108. static UCRC   header_crc;
  109.  
  110. static long   first_hdr_pos;
  111. static int    no_output;
  112.  
  113. static char   *writemode[2]  = { "wb",    "w" };
  114.  
  115. static UCRC   crctable[UCHAR_MAX + 1];
  116.  
  117. /* Functions */
  118.  
  119. static void
  120. make_crctable(void)
  121. {
  122.     uint i, j;
  123.     UCRC r;
  124.  
  125.     for (i = 0; i <= UCHAR_MAX; i++)
  126.     {
  127.         r = i;
  128.         for (j = CHAR_BIT; j > 0; j--)
  129.         {
  130.             if (r & 1)
  131.                 r = (r >> 1) ^ CRCPOLY;
  132.             else
  133.                 r >>= 1;
  134.         }
  135.         crctable[i] = r;
  136.     }
  137. }
  138.  
  139. static void
  140. crc_buf(char *str, uint len)
  141. {
  142.     while (len--)
  143.         UPDATE_CRC(crc, *str++);
  144. }
  145.  
  146. void
  147. error(char *fmt,...)
  148. {
  149.     va_list args;
  150.  
  151.     va_start(args, fmt);
  152.     putc('\n', stdout);
  153.     vprintf(fmt, args);
  154.     putc('\n', stdout);
  155.     va_end(args);
  156.     exit(EXIT_FAILURE);
  157. }
  158.  
  159. static void
  160. strparity(uchar *p)
  161. {
  162.     while (*p)
  163.     {
  164.         FIX_PARITY(*p);
  165.         p++;
  166.     }
  167. }
  168.  
  169. static FILE *
  170. fopen_msg(char *name, char *mode)
  171. {
  172.     FILE *fd;
  173.  
  174.     fd = fopen(name, mode);
  175.     if (fd == NULL)
  176.         error(M_CANTOPEN, name);
  177.     return fd;
  178. }
  179.  
  180. static int
  181. fget_byte(FILE *f)
  182. {
  183.     int c;
  184.  
  185.     if ((c = getc(f)) == EOF)
  186.         error(M_CANTREAD);
  187.     return c & 0xFF;
  188. }
  189.  
  190. static uint
  191. fget_word(FILE *f)
  192. {
  193.     uint b0, b1;
  194.  
  195.     b0 = fget_byte(f);
  196.     b1 = fget_byte(f);
  197.     return (b1 << 8) + b0;
  198. }
  199.  
  200. static ulong
  201. fget_longword(FILE *f)
  202. {
  203.     ulong b0, b1, b2, b3;
  204.  
  205.     b0 = fget_byte(f);
  206.     b1 = fget_byte(f);
  207.     b2 = fget_byte(f);
  208.     b3 = fget_byte(f);
  209.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  210. }
  211.  
  212. static uint
  213. fread_crc(uchar *p, uint n, FILE *f)
  214. {
  215.     n = fread(p, 1, n, f);
  216.     origsize += n;
  217.     crc_buf((char *)p, n);
  218.     return n;
  219. }
  220.  
  221. void
  222. fwrite_txt_crc(uchar *p, uint n)
  223. {
  224.     uchar c;
  225.  
  226.     crc_buf((char *)p, n);
  227.     if (no_output)
  228.         return;
  229.  
  230.     if (file_type == TEXT_TYPE)
  231.     {
  232.         while (n--)
  233.         {
  234.             c = *p++;
  235.             FIX_PARITY(c);
  236.             if (putc(c, outfile) == EOF)
  237.                 error(M_CANTWRIT);
  238.         }
  239.     }
  240.     else
  241.     {
  242.         if (fwrite(p, 1, n, outfile) != n)
  243.             error(M_CANTWRIT);
  244.     }
  245. }
  246.  
  247. void
  248. init_getbits(void)
  249. {
  250.     bitbuf = 0;
  251.     subbitbuf = 0;
  252.     bitcount = 0;
  253.     fillbuf(2 * CHAR_BIT);
  254. }
  255.  
  256. void
  257. fillbuf(int n)                /* Shift bitbuf n bits left, read n bits */
  258. {
  259.     bitbuf <<= n;
  260.     while (n > bitcount)
  261.     {
  262.     bitbuf |= subbitbuf << (n -= bitcount);
  263.     if (compsize != 0)
  264.     {
  265.         compsize--;
  266.         subbitbuf = (uchar) getc(arcfile);
  267.     }
  268.     else
  269.         subbitbuf = 0;
  270.     bitcount = CHAR_BIT;
  271.     }
  272.     bitbuf |= subbitbuf >> (bitcount -= n);
  273. }
  274.  
  275. ushort
  276. getbits(int n)
  277. {
  278.     ushort x;
  279.  
  280.     x = bitbuf >> (2 * CHAR_BIT - n);
  281.     fillbuf(n);
  282.     return x;
  283. }
  284.  
  285. static int
  286. decode_path(char *name)
  287. {
  288.     for ( ; *name; name++)
  289.     {
  290.         if (*name == ARJ_PATH_CHAR)
  291.             *name = PATH_CHAR;
  292.     }
  293.     return 1;
  294. }
  295.  
  296. static void
  297. get_date_str(char *str, ulong tstamp)
  298. {
  299.     sprintf(str, "%04u-%02u-%02u %02u:%02u:%02u",
  300.            ts_year(tstamp), ts_month(tstamp), ts_day(tstamp),
  301.        ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
  302. }
  303.  
  304. static int
  305. parse_path(char *pathname, char *path, char *entry)
  306. {
  307.     char *cptr, *ptr, *fptr;
  308.     short pos;
  309.  
  310.     fptr = NULL;
  311.     for (cptr = PATH_SEPARATORS; *cptr; cptr++)
  312.     {
  313.     if ((ptr = strrchr(pathname, *cptr)) != NULL &&
  314.         (fptr == NULL || ptr > fptr))
  315.         fptr = ptr;
  316.     }
  317.     if (fptr == NULL)
  318.     pos = 0;
  319.     else
  320.     pos = fptr + 1 - pathname;
  321.     if (path != NULL)
  322.     {
  323.        strncpy(path, pathname, pos);
  324.        path[pos] = NULL_CHAR;
  325.     }
  326.     if (entry != NULL)
  327.        strcpy(entry, &pathname[pos]);
  328.     return pos;
  329. }
  330.  
  331. static void
  332. strncopy(char *to, char *from, int len)
  333. {
  334.     int i;
  335.  
  336.     for (i = 1; i < len && *from; i++)
  337.         *to++ = *from++;
  338.     *to = NULL_CHAR;
  339. }
  340.  
  341. void
  342. strupper(char *s)
  343. {
  344.     while (*s)
  345.     {
  346.     *s = (char)toupper(*s);
  347.     s++;
  348.     }
  349. }
  350.  
  351. void *
  352. malloc_msg(size_t size)
  353. {
  354.     char *p;
  355.  
  356.     if ((p = (char *)malloc(size)) == NULL)
  357.         error(M_NOMEMORY);
  358.     return (void *)p;
  359. }
  360.  
  361. static uint
  362. get_word(void)
  363. {
  364.     uint b0, b1;
  365.  
  366.     b0 = get_byte();
  367.     b1 = get_byte();
  368.     return (b1 << 8) + b0;
  369. }
  370.  
  371. static ulong
  372. get_longword(void)
  373. {
  374.     ulong b0, b1, b2, b3;
  375.  
  376.     b0 = get_byte();
  377.     b1 = get_byte();
  378.     b2 = get_byte();
  379.     b3 = get_byte();
  380.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  381. }
  382.  
  383. static long
  384. find_header(FILE *fd, char *name)
  385. {
  386.     long arcpos;
  387.     int c;
  388.  
  389.     for (arcpos = ftell(fd); arcpos < MAXSFX; arcpos++)
  390.     {
  391.         fseek(fd, arcpos, SEEK_SET);
  392.         c = fget_byte(fd);
  393.         while (arcpos < MAXSFX)
  394.     {
  395.             if (c != HEADER_ID_LO)  /* low order first */
  396.                 c = fget_byte(fd);
  397.             else if ((c = fget_byte(fd)) == HEADER_ID_HI)
  398.         break;
  399.         arcpos++;
  400.     }
  401.         if ((headersize = fget_word(fd)) <= HEADERSIZE_MAX)
  402.         {
  403.             crc = CRC_MASK;
  404.             fread_crc(header, headersize, fd);
  405.             if ((crc ^ CRC_MASK) == fget_crc(fd))
  406.             {
  407.                 fseek(fd, arcpos, SEEK_SET);
  408.                 return arcpos;
  409.             }
  410.         }
  411.     }
  412.     error(M_NOTARJ, name);
  413.     return 0;
  414. }
  415.  
  416. static int
  417. read_header(int first, FILE *fd, char *name)
  418. {
  419.     ushort extheadersize, header_id;
  420.  
  421.     header_id = fget_word(fd);
  422.     if (header_id != HEADER_ID)
  423.     {
  424.     if (first)
  425.             error(M_NOTARJ, name);
  426.     else
  427.         error(M_BADHEADR);
  428.     }
  429.  
  430.     headersize = fget_word(fd);
  431.     if (headersize == 0)
  432.     return 0;        /* end of archive */
  433.     if (headersize > HEADERSIZE_MAX)
  434.     error(M_BADHEADR);
  435.  
  436.     crc = CRC_MASK;
  437.     fread_crc(header, headersize, fd);
  438.     header_crc = fget_crc(fd);
  439.     if ((crc ^ CRC_MASK) != header_crc)
  440.     error(M_HEADRCRC);
  441.  
  442.     setup_get(header);
  443.     first_hdr_size = get_byte();
  444.     arj_nbr = get_byte();
  445.     arj_x_nbr = get_byte();
  446.     host_os = get_byte();
  447.     arj_flags = get_byte();
  448.     method = get_byte();
  449.     file_type = get_byte();
  450.     (void)get_byte();
  451.     time_stamp = get_longword();
  452.     compsize = get_longword();
  453.     origsize = get_longword();
  454.     file_crc = get_crc();
  455.     entry_pos = get_word();
  456.     file_mode = get_word();
  457.     host_data = get_word();
  458.  
  459.     hdr_filename = (char *)&header[first_hdr_size];
  460.     strncopy(filename, hdr_filename, sizeof(filename));
  461.     if (host_os != OS)
  462.         strparity((uchar *)filename);
  463.     if ((arj_flags & PATHSYM_FLAG) != 0)
  464.         decode_path(filename);
  465.  
  466.     hdr_comment = (char *)&header[first_hdr_size + strlen(hdr_filename) + 1];
  467.     strncopy(comment, hdr_comment, sizeof(comment));
  468.     if (host_os != OS)
  469.         strparity((uchar *)comment);
  470.  
  471.     while ((extheadersize = fget_word(fd)) != 0)
  472.     fseek(fd, extheadersize + 2, SEEK_CUR);
  473.  
  474.     return 1;            /* success */
  475. }
  476.  
  477. static void
  478. skip(void)
  479. {
  480.     fseek(arcfile, compsize, SEEK_CUR);
  481. }
  482.  
  483. static void
  484. unstore(void)
  485. {
  486.     uint n;
  487.     long pos;
  488.     char *buffer;
  489.  
  490.     buffer = (char *)malloc_msg(BUFFERSIZE);
  491.     pos = ftell(arcfile);
  492.     n = (uint)(BUFFERSIZE - (pos % BUFFERSIZE));
  493.     n = compsize > (long)n ? n : (uint)compsize;
  494.     while (compsize > 0)
  495.     {
  496.     if (fread(buffer, 1, n, arcfile) != n)
  497.             error(M_CANTREAD);
  498.         putc('.', stdout);
  499.     compsize -= n;
  500.         fwrite_txt_crc((uchar *)buffer, n);
  501.         n = compsize > BUFFERSIZE ? BUFFERSIZE : (uint)compsize;
  502.     }
  503.     free(buffer);
  504. }
  505.  
  506. static int
  507. check_flags(void)
  508. {
  509.     if (arj_x_nbr > ARJ_X_VERSION)
  510.     {
  511.         printf(M_UNKNVERS, arj_x_nbr);
  512.         printf(M_SKIPPED, filename);
  513.     skip();
  514.     return -1;
  515.     }
  516.     if ((arj_flags & GARBLE_FLAG) != 0)
  517.     {
  518.         printf(M_ENCRYPT);
  519.         printf(M_SKIPPED, filename);
  520.     skip();
  521.     return -1;
  522.     }
  523.     if (method < 0 || method > MAXMETHOD || (method == 4 && arj_nbr == 1))
  524.     {
  525.         printf(M_UNKNMETH, method);
  526.         printf(M_SKIPPED, filename);
  527.     skip();
  528.     return -1;
  529.     }
  530.     if (file_type != BINARY_TYPE && file_type != TEXT_TYPE)
  531.     {
  532.         printf(M_UNKNTYPE, file_type);
  533.         printf(M_SKIPPED, filename);
  534.     skip();
  535.     return -1;
  536.     }
  537.     return 0;
  538. }
  539.  
  540. static int
  541. extract(void)
  542. {
  543.     if (check_flags())
  544.         return 0;
  545.  
  546.     if (no_output)
  547.         printf(M_TESTING, filename);
  548.     else
  549.     {
  550.         if (file_exists(filename))
  551.         {
  552.             printf(M_FEXISTS, filename);
  553.             printf(M_SKIPPED, filename);
  554.             skip();
  555.             return 0;
  556.         }
  557.         outfile = fopen(filename, writemode[file_type & 1]);
  558.         if (outfile == NULL)
  559.         {
  560.             printf(M_CANTOPEN, filename);
  561.             putchar('\n');
  562.             skip();
  563.             return 0;
  564.         }
  565.         printf(M_EXTRACT, filename);
  566.         if (host_os != OS && file_type == BINARY_TYPE)
  567.             printf(M_DIFFHOST);
  568.     }
  569.  
  570.     printf("  ");
  571.  
  572.     crc = CRC_MASK;
  573.     if (file_type == BINARY_TYPE || file_type == TEXT_TYPE)
  574.     {
  575.         if (method == 0)
  576.             unstore();
  577.         else if (method == 1 || method == 2 || method == 3)
  578.             decode();
  579.         else if (method == 4)
  580.             decode_f();
  581.     }
  582.  
  583.     if (no_output == 0)
  584.     {
  585.         if (file_type == BINARY_TYPE || file_type == TEXT_TYPE)
  586.             fclose(outfile);
  587.         if (host_os == OS)
  588.             set_fmode(filename, file_mode);
  589.         set_ftime(filename, time_stamp);
  590.     }
  591.  
  592.     if ((crc ^ CRC_MASK) == file_crc)
  593.         printf(M_CRCOK);
  594.     else
  595.     {
  596.         printf(M_CRCERROR);
  597.     error_count++;
  598.     }
  599.     return 1;
  600. }
  601.  
  602. static void
  603. execute_cmd(void)
  604. {
  605.     int file_count;
  606.     char date_str[22];
  607.  
  608.     first_hdr_pos = 0;
  609.     time_stamp = 0;
  610.     first_hdr_size = FIRST_HDR_SIZE;
  611.  
  612.     arcfile = fopen_msg(arc_name, "rb");
  613.  
  614.     printf(M_PROCARC, arc_name);
  615.  
  616.     first_hdr_pos = find_header(arcfile, arc_name);
  617.     fseek(arcfile, first_hdr_pos, SEEK_SET);
  618.     if (!read_header(1, arcfile, arc_name))
  619.         error(M_BADCOMNT);
  620.     get_date_str(date_str, time_stamp);
  621.     printf(M_ARCDATE, date_str);
  622.  
  623.     file_count = 0;
  624.     while (read_header(0, arcfile, arc_name))
  625.     {
  626.         if (extract())
  627.             file_count++;
  628.     }
  629.  
  630.     printf(M_NBRFILES, file_count);
  631.  
  632.     fclose(arcfile);
  633. }
  634.  
  635. int
  636. main(int argc, char *argv[])
  637. {
  638.     int i, j, lastc;
  639.  
  640.     printf(M_VERSION);
  641.  
  642.     no_output = 0;
  643.     if (argc == 3 && strcmp(argv[2], "NUL") == 0)
  644.     {
  645.         no_output = 1;
  646.     }
  647.     else if (argc != 2)
  648.     {
  649.         printf(M_USAGE);
  650.         return EXIT_SUCCESS;
  651.     }
  652.  
  653.     strncopy(arc_name, argv[1], FNAME_MAX);
  654.     case_path(arc_name);
  655.     i = strlen(arc_name);
  656.     j = parse_path(arc_name, NULL, NULL);
  657.     lastc = arc_name[i - 1];
  658.     if (lastc == ARJ_DOT)
  659.         arc_name[i - 1] = NULL_CHAR;
  660.     else if (strchr(&arc_name[j], ARJ_DOT) == NULL)
  661.         strcat(arc_name, M_SUFFIX);
  662.  
  663.     make_crctable();
  664.  
  665.     error_count = 0;
  666.     arcfile = NULL;
  667.     outfile = NULL;
  668.  
  669.     execute_cmd();
  670.  
  671.     if (error_count > 0)
  672.     error(M_ERRORCNT, error_count);
  673.  
  674.     return EXIT_SUCCESS;
  675. }
  676.  
  677. /* end UNARJ.C */
  678.