home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / utils / arj.zip / AV.C < prev    next >
C/C++ Source or Header  |  1990-12-28  |  14KB  |  568 lines

  1. /* AV.C, ARJ, R JUNG, 12/09/90
  2. /* Display the contents of an ARJ archive
  3. /* Copyright (c) 1990 by Robert K Jung.  All rights reserved.
  4. /*
  5. /* License policy:
  6. /*   You are free to use this code for any purpose as long as you make
  7. /*   mention of its original author.
  8. /*
  9. /* Description:
  10. /*   This program can be compiled under Turbo C 2.0, Turbo C++ 1.0 and
  11. /*   QuickC 2.5.
  12. /*
  13. /* Modification history:
  14. /* Date      Programmer  Description of modification.
  15. /* 12/09/90  R. Jung     Increased comment size to 2048.  Added length check
  16. /*                       to comment processing.  Corrected copyright display.
  17. /*                       Added more string length checking.
  18. /* 11/15/90  R. Jung     Initial coding.
  19. /*
  20. */
  21.  
  22. #include <stdio.h>
  23. #include <limits.h>
  24. #include <stdlib.h>
  25. #include <stdarg.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28.  
  29. typedef unsigned char  uchar;   /*  8 bits or more */
  30. typedef unsigned int   uint;    /* 16 - 32 bits or more */
  31. typedef unsigned short ushort;  /* 16 bits or more */
  32. typedef unsigned long  ulong;   /* 32 bits or more */
  33.  
  34. typedef ulong UCRC;
  35.  
  36. #define FA_RDONLY    0x01        /* Read only attribute */
  37. #define FA_HIDDEN    0x02        /* Hidden file */
  38. #define FA_SYSTEM    0x04        /* System file */
  39. #define FA_LABEL    0x08        /* Volume label */
  40. #define FA_DIREC    0x10        /* Directory */
  41. #define FA_ARCH        0x20        /* Archive */
  42.  
  43. /* ********************************************************* */
  44. /*
  45. /* Structure of archive block (low order byte first):
  46. /*
  47. /*  2  header id (comment and local file) = 0xEA60 or 60000U
  48. /*  2  basic header size (from 'first_hdr_size' thru 'comment' below)
  49. /*         = first_hdr_size + strlen(filename) + 1 + strlen(comment) + 1
  50. /*         = 0 if end of archive
  51. /*
  52. /*  1  first_hdr_size (size up to 'extra data')
  53. /*  1  archiver version number
  54. /*  1  minimum archiver version to extract
  55. /*  1  host OS     (0 = MSDOS, 1 = PRIMOS, 2 = UNIX, 3 = AMIGA, 4 = MACDOS)
  56. /*  1  arj flags (0x01 = GARBLED_FLAG, 0x02 = RESERVED)
  57. /*               (0x04 = VOLUME_FLAG,  0x08 = EXTFILE_FLAG)
  58. /*               (0x10 = PATHSYM_FLAG)
  59. /*  1  method    (0 = stored, 1 = compressed most ... 4 compressed fastest)
  60. /*  1  file type (0 = binary, 1 = text, 2 = comment header)
  61. /*  1  reserved
  62. /*  4  date time stamp modified
  63. /*  4  compressed size
  64. /*  4  original size
  65. /*  4  original file's CRC
  66. /*  2  file access mode
  67. /*  2  entryname position in filename
  68. /*  2  host data
  69. /*  ?  extra data
  70. /*     4 bytes for extended file position
  71. /*
  72. /*  ?  filename (null-terminated)
  73. /*  ?  comment    (null-terminated)
  74. /*
  75. /*  4  basic header CRC
  76. /*
  77. /*  2  1st extended header size (0 if none)
  78. /*  ?  1st extended header
  79. /*  4  1st extended header's CRC
  80. /*  ...
  81. /*  ?  compressed file
  82. /*
  83. /* ********************************************************* */
  84.  
  85. /* ********************************************************* */
  86. /*                                 */
  87. /*     Time stamp format:                     */
  88. /*                                 */
  89. /*    31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16      */
  90. /*     |<----- year-1980 ----->|<- month ->|<-- day -->|     */
  91. /*                                 */
  92. /*    15 14 13 12 11 10  9  8  7  6  5  4  3    2  1  0      */
  93. /*     |<--- hour --->|<---- minute --->|<- second/2 ->|     */
  94. /*                                 */
  95. /* ********************************************************* */
  96.  
  97. #define NULL_CHAR       '\0'
  98. #define PATH_CHAR       '\\'
  99. #define FNAME_MAX       512
  100. #define MAXSFX        25000
  101. #define OS                0
  102. #define HOST_OS_NAMES  { "MS-DOS","PRIMOS","UNIX","AMIGA","MAC-OS",NULL }
  103.  
  104. #define HEADER_ID      60000U
  105. #define FIRST_HDR_SIZE    30
  106. #define COMMENT_MAX     2048
  107. #define HEADERSIZE_MAX   (FIRST_HDR_SIZE + 10 + FNAME_MAX + COMMENT_MAX)
  108. #define BINARY_TYPE        0 /* This must line up with binary/text strings */
  109. #define TEXT_TYPE          1
  110. #define COMMENT_TYPE       2
  111. #define GARBLE_FLAG     0x01
  112. #define VOLUME_FLAG     0x04
  113. #define EXTFILE_FLAG    0x08
  114. #define PATHSYM_FLAG    0x10
  115.  
  116. #define CRC_MASK        0xFFFFFFFFUL
  117. #define ASCII_MASK      0x7F
  118. #define ARJ_PATH_CHAR   '/'
  119. #define CRCPOLY         0xEDB88320UL
  120.  
  121. #define UPDATE_CRC(crc, c)  \
  122.         crc = crctable[(uchar)crc ^ (uchar)(c)] ^ (crc >> CHAR_BIT)
  123. #define FIX_PARITY(c)   c &= ASCII_MASK
  124. #define get_tstamp(yy, mm, dd, hr, mn, sc) \
  125.     ( (((ulong)(yy - 1980)) << 25) + ((ulong)mm << 21) + ((ulong)dd << 16) + \
  126.     ((ulong)hr << 11) + (mn << 5) + (sc / 2) )
  127.  
  128. #define ts_year(ts)  ((uint)((ts >> 25) & 0x7f) + 1980)
  129. #define ts_month(ts) ((uint)(ts >> 21) & 0x0f)      /* 1..12 means Jan..Dec */
  130. #define ts_day(ts)   ((uint)(ts >> 16) & 0x1f)      /* 1..31 means 1st..31st */
  131. #define ts_hour(ts)  ((uint)(ts >> 11) & 0x1f)
  132. #define ts_min(ts)   ((uint)(ts >> 5) & 0x3f)
  133. #define ts_sec(ts)   ((uint)((ts & 0x1f) * 2))
  134.  
  135. #define get_crc()       get_longword()
  136. #define fget_crc(f)     fget_longword(f)
  137.  
  138. #define setup_get(PTR)  (get_ptr = (PTR))
  139. #define get_byte()      ((uchar)(*get_ptr++ & 0xff))
  140. #define setup_put(PTR)  (put_ptr = (PTR))
  141.  
  142. static UCRC   crc;
  143. static FILE   *arcfile;
  144. static long   compsize;
  145. static long   origsize;
  146. static uchar  header[HEADERSIZE_MAX];
  147. static char   arc_name[FNAME_MAX];
  148. static char   filename[FNAME_MAX];
  149. static char   comment[COMMENT_MAX];
  150. static char   *hdr_filename;
  151. static char   *hdr_comment;
  152. static ushort headersize;
  153. static uchar  first_hdr_size;
  154. static uchar  arj_nbr;
  155. static uchar  arj_x_nbr;
  156. static uchar  host_os;
  157. static uchar  arj_flags;
  158. static short  method;
  159. static short  file_type;
  160. static ushort file_mode;
  161. static ulong  time_stamp;
  162. static short  entry_pos;
  163. static ushort host_data;
  164. static uchar  *get_ptr;
  165. static UCRC   file_crc;
  166. static UCRC   header_crc;
  167. static long   torigsize;
  168. static long   tcompsize;
  169.  
  170. static UCRC   crctable[UCHAR_MAX + 1];
  171.  
  172. void
  173. error(char *fmt,...)
  174. {
  175.     va_list args;
  176.  
  177.     va_start(args, fmt);
  178.     fputc('\n', stdout);
  179.     vfprintf(stdout, fmt, args);
  180.     fputc('\n', stdout);
  181.     va_end(args);
  182.     exit(EXIT_FAILURE);
  183. }
  184.  
  185. void
  186. make_crctable(void)
  187. {
  188.     uint i, j;
  189.     UCRC r;
  190.  
  191.     for (i = 0; i <= UCHAR_MAX; i++)
  192.     {
  193.         r = i;
  194.         for (j = 0; j < CHAR_BIT; j++)
  195.         {
  196.             if (r & 1)
  197.                 r = (r >> 1) ^ CRCPOLY;
  198.             else
  199.                 r >>= 1;
  200.         }
  201.         crctable[i] = r;
  202.     }
  203. }
  204.  
  205. void
  206. crc_buf(char *str, uint len)
  207. {
  208.     while (len--)
  209.         UPDATE_CRC(crc, *str++);
  210. }
  211.  
  212. void
  213. strparity(uchar *p)
  214. {
  215.     while (*p)
  216.     {
  217.         FIX_PARITY(*p);
  218.         p++;
  219.     }
  220. }
  221.  
  222. void
  223. get_date_str(char *str, ulong tstamp)
  224. {
  225.     sprintf(str, "%02u-%02u-%02u %02u:%02u:%02u",
  226.            ts_year(tstamp)-1900, ts_month(tstamp), ts_day(tstamp),
  227.            ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
  228. }
  229.  
  230. int
  231. parse_path(char *pathname)
  232. {
  233.     char *cptr, *ptr, *fptr;
  234.     short pos;
  235.  
  236.     fptr = NULL;
  237.     for (cptr = ":\\"; *cptr; cptr++)
  238.     {
  239.         if ((ptr = strrchr(pathname, *cptr)) != NULL &&
  240.                 (fptr == NULL || ptr > fptr))
  241.             fptr = ptr;
  242.     }
  243.     if (fptr == NULL)
  244.         pos = 0;
  245.     else
  246.         pos = fptr + 1 - pathname;
  247.     return pos;
  248. }
  249.  
  250. int
  251. decode_path(char *name)
  252. {
  253.     for ( ; *name; name++)
  254.     {
  255.         if (*name == ARJ_PATH_CHAR)
  256.             *name = PATH_CHAR;
  257.     }
  258.     return 1;
  259. }
  260.  
  261. int
  262. fget_byte(FILE *f)
  263. {
  264.     int c;
  265.  
  266.     if ((c = fgetc(f)) == EOF)
  267.         error("Can't read file or unexpected end of file");
  268.     return c & 0xFF;
  269. }
  270.  
  271. uint
  272. fget_word(FILE *f)
  273. {
  274.     uint b0, b1;
  275.  
  276.     b0 = fget_byte(f);
  277.     b1 = fget_byte(f);
  278.     return (b1 << 8) + b0;
  279. }
  280.  
  281. ulong
  282. fget_longword(FILE *f)
  283. {
  284.     ulong b0, b1, b2, b3;
  285.  
  286.     b0 = fget_byte(f);
  287.     b1 = fget_byte(f);
  288.     b2 = fget_byte(f);
  289.     b3 = fget_byte(f);
  290.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  291. }
  292.  
  293. uint
  294. fread_crc(uchar *p, uint n, FILE *f)
  295. {
  296.     n = fread(p, 1, n, f);
  297.     origsize += n;
  298.     crc_buf((char *)p, n);
  299.     return n;
  300. }
  301.  
  302. void
  303. get_mode_str(char *str, ushort mode)
  304. {
  305.     strcpy(str, "---W");
  306.     if (mode & FA_ARCH)
  307.         str[0] = 'A';
  308.     if (mode & FA_SYSTEM)
  309.         str[1] = 'S';
  310.     if (mode & FA_HIDDEN)
  311.         str[2] = 'H';
  312.     if (mode & FA_RDONLY)
  313.         str[3] = 'R';
  314. }
  315.  
  316. static uint
  317. get_word(void)
  318. {
  319.     uint b0, b1;
  320.  
  321.     b0 = get_byte();
  322.     b1 = get_byte();
  323.     return (b1 << 8) + b0;
  324. }
  325.  
  326. static ulong
  327. get_longword(void)
  328. {
  329.     ulong b0, b1, b2, b3;
  330.  
  331.     b0 = get_byte();
  332.     b1 = get_byte();
  333.     b2 = get_byte();
  334.     b3 = get_byte();
  335.     return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  336. }
  337.  
  338. static void
  339. strncopy(char *to, char *from, int len)
  340. {
  341.     int i;
  342.  
  343.     for (i = 1; i < len; i++)
  344.         *to++ = *from++;
  345.     *to = NULL_CHAR;
  346. }
  347.  
  348. static long
  349. find_header(void)
  350. {
  351.     long arcpos;
  352.     uchar c;
  353.  
  354.     for (arcpos = 0; arcpos < MAXSFX; arcpos++)
  355.     {
  356.         fseek(arcfile, arcpos, SEEK_SET);
  357.         c = (uchar)fget_byte(arcfile);
  358.         while (1)
  359.         {
  360.             if (c != (uchar)HEADER_ID)      /* low order byte first */
  361.                 c = (uchar)fget_byte(arcfile);
  362.             else if ((c = (uchar)fget_byte(arcfile)) == ((ushort)HEADER_ID >> 8))
  363.                 break;
  364.             arcpos++;
  365.         }
  366.         if ((headersize = fget_word(arcfile)) > 0 && headersize <= HEADERSIZE_MAX)
  367.         {
  368.             crc = CRC_MASK;
  369.             fread_crc(header, headersize, arcfile);
  370.             if ((crc ^ CRC_MASK) == fget_crc(arcfile))
  371.             {
  372.                 fseek(arcfile, arcpos, SEEK_SET);
  373.                 break;
  374.             }
  375.         }
  376.     }
  377.     return arcpos;
  378. }
  379.  
  380. static int
  381. read_header(void)
  382. {
  383.     ushort extheadersize;
  384.  
  385.     if (fget_word(arcfile) != HEADER_ID)
  386.         error("Bad header");
  387.  
  388.     if ((headersize = fget_word(arcfile)) == 0)
  389.         return 0;               /* end of archive */
  390.     if (headersize > HEADERSIZE_MAX)
  391.         error("Bad header");
  392.  
  393.     crc = CRC_MASK;
  394.     fread_crc(header, headersize, arcfile);
  395.     header_crc = fget_crc(arcfile);
  396.     if ((crc ^ CRC_MASK) != header_crc)
  397.         error("Header CRC error");
  398.  
  399.     setup_get(header);
  400.     first_hdr_size = get_byte();
  401.     arj_nbr = get_byte();
  402.     arj_x_nbr = get_byte();
  403.     host_os = get_byte();
  404.     arj_flags = get_byte();
  405.     method = get_byte();
  406.     file_type = get_byte();
  407.     (void) get_byte();
  408.     time_stamp = get_longword();
  409.     compsize = get_longword();
  410.     origsize = get_longword();
  411.     file_crc = get_crc();
  412.     entry_pos = get_word();
  413.     file_mode = get_word();
  414.     host_data = get_word();
  415.  
  416.     hdr_filename = (char *)&header[first_hdr_size];
  417.     strncopy(filename, hdr_filename, FNAME_MAX);
  418.     if (host_os != OS)
  419.         strparity((uchar *)filename);
  420.     if ((arj_flags & PATHSYM_FLAG) != 0)
  421.         decode_path(filename);
  422.  
  423.     hdr_comment = (char *)&header[first_hdr_size + strlen(hdr_filename) + 1];
  424.     strncopy(comment, hdr_comment, sizeof(comment));
  425.     if (host_os != OS)
  426.         strparity((uchar *)comment);
  427.  
  428.     while ((extheadersize = fget_word(arcfile)) != 0)
  429.         fseek(arcfile, extheadersize + 2, SEEK_CUR);
  430.  
  431.     return 1;                   /* success */
  432. }
  433.  
  434. static void
  435. skip(void)
  436. {
  437.     fseek(arcfile, compsize, SEEK_CUR);
  438. }
  439.  
  440. uint
  441. ratio(long a, long b)         /* [(1000a + [b/2]) / b] */
  442. {
  443.    int i;
  444.  
  445.    for (i = 0; i < 3; i++)
  446.        if (a <= LONG_MAX / 10)
  447.            a *= 10;
  448.        else
  449.            b /= 10;
  450.    if ((long) (a + (b >> 1)) < a)
  451.    {
  452.        a >>= 1;
  453.        b >>= 1;
  454.    }
  455.    if (b == 0)
  456.        return 0;
  457.    return (uint) ((a + (b >> 1)) / b);
  458. }
  459.  
  460. static void
  461. list_start(void)
  462. {
  463.     printf("Filename     ");
  464.     printf("  Original Compressed Ratio DateTime modified CRC-32   Attr TPMGVX\n");
  465.     printf("------------ "
  466.            "---------- ---------- ----- ----------------- -------- ---- ------\n");
  467. }
  468.  
  469. static void
  470. list_arc(int count)
  471. {
  472.     uint r;
  473.     int garble_mode, path_mode, volume_mode, extfil_mode;
  474.     char date_str[20], fmode_str[10];
  475.     char mode[2] = { 'B', 'T' };  /* Binary, Text */
  476.     char pthf[2] = { ' ', '+' };
  477.     char pwdf[2] = { ' ', 'G' };  /* plain, encrypted */
  478.     char volf[2] = { ' ', 'V' };
  479.     char extf[2] = { ' ', 'X' };
  480.  
  481.     if (count == 0)
  482.         list_start();
  483.  
  484.     garble_mode = ((arj_flags & GARBLE_FLAG) != 0);
  485.     path_mode = (entry_pos > 0);
  486.     volume_mode = ((arj_flags & VOLUME_FLAG) != 0);
  487.     extfil_mode = ((arj_flags & EXTFILE_FLAG) != 0);
  488.     r = ratio(compsize, origsize);
  489.     torigsize += origsize;
  490.     tcompsize += compsize;
  491.     get_date_str(date_str, time_stamp);
  492.     strcpy(fmode_str, "    ");
  493.     if (host_os == OS)
  494.         get_mode_str(fmode_str, file_mode);
  495.     if (strlen(&filename[entry_pos]) > 12)
  496.         printf("%-12s\n             ", &filename[entry_pos]);
  497.     else
  498.         printf("%-12s ", &filename[entry_pos]);
  499.     printf("%10ld %10ld %u.%03u %s %08lX %4s %c%c%u%c\n",
  500.         origsize, compsize, r / 1000, r % 1000, date_str, file_crc,
  501.         fmode_str, mode[file_type & 1], pthf[path_mode],
  502.         method, pwdf[garble_mode], volf[volume_mode], extf[extfil_mode]);
  503. }
  504.  
  505. void
  506. execute_cmd(void)
  507. {
  508.     int count;
  509.     uint r;
  510.  
  511.     torigsize = 0;
  512.     tcompsize = 0;
  513.  
  514.     if ((arcfile = fopen(arc_name, "rb")) == NULL)
  515.         error("Can't open: %s", arc_name);
  516.  
  517.     find_header();
  518.     if (!read_header())
  519.         error("Bad archive header");
  520.  
  521.     count = 0;
  522.     while (read_header())
  523.     {
  524.         list_arc(count);
  525.         ++count;
  526.         skip();
  527.     }
  528.  
  529.     if (count <= 0)
  530.         printf("     0 files\n");
  531.     else
  532.     {
  533.         printf("------------ ---------- ---------- -----\n");
  534.         r = ratio(tcompsize, torigsize);
  535.         printf(" %5d files %10ld %10ld %u.%03u\n",
  536.             count, torigsize, tcompsize, r / 1000, r % 1000);
  537.     }
  538.     fclose(arcfile);
  539. }
  540.  
  541. int
  542. main(int argc, char *argv[])
  543. {
  544.     int i, j, lastc;
  545.  
  546.     printf("AV - ARJ file viewer - Rev 1.1, Copyright (c) 1990 Robert K Jung\n");
  547.  
  548.     if (argc != 2)
  549.         error("Usage:  AV archive_name[.ARJ]");
  550.  
  551.     make_crctable();
  552.  
  553.     strncopy(arc_name, argv[1], FNAME_MAX);
  554.     i = strlen(arc_name);
  555.     j = parse_path(arc_name);
  556.     lastc = arc_name[i - 1];
  557.     if (lastc == '.')
  558.         arc_name[i - 1] = NULL_CHAR;
  559.     else if (strrchr(&arc_name[j], '.') == NULL)
  560.         strcat(arc_name, ".ARJ");
  561.  
  562.     execute_cmd();
  563.  
  564.     return EXIT_SUCCESS;
  565. }
  566.  
  567. /* end AV.C */
  568.