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