home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume14 / unzip-3.1 / part03 / unzip.c < prev   
Encoding:
C/C++ Source or Header  |  1990-09-20  |  22.4 KB  |  856 lines

  1. /*
  2.  * Copyright 1989 Samuel H. Smith;  All rights reserved
  3.  *
  4.  * Do not distribute modified versions without my permission.
  5.  * Do not remove or alter this notice or any other copyright notice.
  6.  * If you use this in your own program you must distribute source code.
  7.  * Do not use any of this in a commercial product.
  8.  *
  9.  */
  10.  
  11. /*
  12.  * UnZip - A simple zipfile extract utility
  13.  *
  14.  * Compile-time definitions:
  15.  * See the Makefile for details, explanations, and all the current
  16.  * system makerules.
  17.  *
  18.  * If you have to add a new one for YOUR system, please forward the
  19.  * new Makefile to kirsch@usasoc.soc.mil for distribution.
  20.  * Be SURE to give FULL details on your system (hardware, OS, versions,
  21.  * processor, whatever) that made it unique.
  22.  *
  23.  * REVISION HISTORY : See history.307 (or whatever current version is)
  24.  *
  25.  */
  26.  
  27. #include "unzip.h"    /* v3.05 a BUNCH of ifdefs, etc.
  28.              * split out to reduce file size.
  29.              * David Kirschbaum
  30.              */
  31.  
  32. char *fnames[2] = { /* default filenames vector */
  33.     "*",
  34.     NULL
  35. };
  36. char **fnv = &fnames[0];
  37.  
  38. int tflag;      /* -t: test */
  39. int vflag;      /* -v: view directory */
  40. int cflag;      /* -c: output to stdout (JC) */
  41. int aflag;      /* -a: do ascii to ebcdic translation 2.0f */
  42.                 /*     OR <cr><nl> to <nl> conversion  */
  43. int mflag;    /* -m: map member filenames to lower case v2.0j */
  44. int CR_flag = 0; /* When last char of buffer == CR */
  45.  
  46. int members;
  47. longint csize;
  48. longint ucsize;
  49. longint tot_csize;
  50. longint tot_ucsize;
  51.  
  52.  
  53. /* ----------------------------------------------------------- */
  54. /*
  55.  * shrink/reduce working storage
  56.  *
  57.  */
  58.  
  59. int factor;
  60. /* really need only 256, but prefix_of, which shares the same
  61.    storage, is just over 16K */
  62. byte followers[257][64];    /* also lzw prefix_of, s-f lit_nodes */
  63. byte Slen[256];
  64.  
  65. typedef short hsize_array_integer[hsize+1]; /* was used for prefix_of */
  66. typedef byte hsize_array_byte[hsize+1];
  67.  
  68. short *prefix_of = (short *) followers; /* share reduce/shrink storage */
  69. hsize_array_byte suffix_of;     /* also s-f length_nodes */
  70. hsize_array_byte stack;         /* also s-f distance_nodes */
  71.  
  72. int codesize;
  73. int maxcode;
  74. int free_ent;
  75. int maxcodemax;
  76. int offset;
  77. int sizex;
  78.  
  79. /* Code now begins ( .. once more into the Valley of Death.. ) */
  80.  
  81.  
  82. #ifdef NOTINT16     /* v2.0c */
  83. UWORD makeword(b)
  84. byte * b;
  85.  /* convert Intel style 'short' integer to non-Intel non-16-bit
  86.   * host format
  87.   */
  88. {
  89. /*
  90.     return  ( ((UWORD) (b[1]) << 8)
  91.             | (UWORD) (b[0])
  92.             );
  93. */
  94.     return  ( ( b[1] << 8)
  95.             | b[0]
  96.             );
  97. }
  98.  
  99. longint makelong(sig)
  100. byte *sig;
  101.  /* convert intel style 'long' variable to non-Intel non-16-bit
  102.   * host format
  103.   */
  104. {
  105.     return ( ((longint) sig[3]) << 24)
  106.           + ( ((longint) sig[2]) << 16)
  107.           + ( ((longint) sig[1]) << 8)
  108.           +   ((longint)  sig[0]) ;
  109. }
  110. #endif  /* NOTINT16 */
  111.  
  112. #ifdef HIGH_LOW
  113.  
  114. void swap_bytes(wordp)
  115. UWORD *wordp;
  116.  /* convert Intel style 'short int' variable to host format */
  117. {
  118.     char *charp = (char *) wordp;
  119.     char temp;
  120.  
  121.     temp = charp[0];
  122.     charp[0] = charp[1];
  123.     charp[1] = temp;
  124. }
  125.  
  126. void swap_lbytes(longp)
  127. longint *longp;
  128.  /* convert intel style 'long' variable to host format */
  129. {
  130.     char *charp = (char *) longp;
  131.     char temp[4];
  132.  
  133.     temp[3] = charp[0];
  134.     temp[2] = charp[1];
  135.     temp[1] = charp[2];
  136.     temp[0] = charp[3];
  137.  
  138.     charp[0] = temp[0];
  139.     charp[1] = temp[1];
  140.     charp[2] = temp[2];
  141.     charp[3] = temp[3];
  142. }
  143.  
  144. #endif /* HIGH_LOW */
  145. /* ----------------------------------------------------------- */
  146.  
  147. #include "file_io.c"        /* v3.05 file-related vars, functions */
  148.  
  149. #include "unreduce.c"        /* v3.05 */
  150.  
  151. #include "unshrink.c"        /* v3.05 */
  152.  
  153. #include "unimplod.c"        /* v3.05 */
  154.  
  155.  
  156. /* ---------------------------------------------------------- */
  157.  
  158. /*
  159.  Length  Method   Size  Ratio   Date    Time   CRC-32    Name
  160.  ------  ------   ----- -----   ----    ----   ------    ----
  161.   44004  Implode  13041  71%  11-02-89  19:34  88420727  DIFF3.C
  162.  */
  163.  
  164. void dir_member()
  165. {
  166.     char *method;
  167.     int ratio;
  168.     int yr, mo, dy, hh, mm;
  169.  
  170.     yr = (((lrec.last_mod_file_date >> 9) & 0x7f) + 80);
  171.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f);
  172.     dy = (lrec.last_mod_file_date & 0x1f);
  173.  
  174.     hh = ((lrec.last_mod_file_time >> 11) & 0x1f);
  175.     mm = ((lrec.last_mod_file_time >> 5) & 0x3f);
  176.  
  177.     switch (lrec.compression_method)  {
  178.     case 0:
  179.         method = "Stored";
  180.         break;
  181.     case 1:
  182.         method = "Shrunk";
  183.         break;
  184.     case 2:
  185.     case 3:
  186.     case 4:
  187.     case 5:
  188.         method = "Reduced";
  189.         break;
  190.     case 6:
  191.         method = "Implode";
  192.         break;
  193.     }
  194.  
  195.     if (ucsize != 0)  {
  196.         ratio = (int) ((1000L * (ucsize - csize)) / ucsize);
  197.         if ((ratio % 10) >= 5)
  198.             ratio += 10;
  199.     }
  200.     else
  201.         ratio = 0;  /* can .zip contain 0-size file? */
  202.  
  203. #ifdef NOTINT16     /* v2.0c */
  204.     printf("%7ld  %-7s%7ld %3d%%  %02d-%02d-%02d  %02d:%02d  \
  205. %08lx  %s\n", ucsize, method, csize,
  206.         ratio / 10, mo, dy, yr, hh, mm,
  207.         lrec.crc32, filename);
  208. #else   /* !NOTINT16 */
  209.     printf("%7ld  %-7s%7ld %3d%%  %02d-%02d-%02d  %02d:%02d  \
  210. %08lx  %s\n", ucsize, method, csize,
  211.         ratio / 10, mo, dy, yr, hh, mm,
  212.         LONGI(lrec.crc32), filename);
  213. #endif  /* NOTINT16 */
  214.     tot_ucsize += ucsize;
  215.     tot_csize += csize;
  216.     ++members;
  217. }
  218.  
  219. /* ---------------------------------------------------------- */
  220.  
  221. void skip_member()
  222. {
  223.     register long pos;
  224.     long endbuf;
  225.     int offset;
  226.  
  227.     endbuf = lseek(zipfd, 0L, SEEK_CUR);    /* 1st byte beyond inbuf */
  228.     pos = endbuf - incnt;                   /* 1st compressed byte */
  229.     pos += csize;                           /* next header signature */
  230.     if (pos < endbuf)  {
  231.         incnt -= csize;
  232.         inptr += csize;
  233.     }
  234.     else  {
  235.         offset = pos % BSIZE;               /* offset within block */
  236.         pos = (pos / BSIZE) * BSIZE;        /* block start */
  237.         lseek(zipfd, pos, SEEK_SET);
  238.         incnt = read(zipfd, inbuf, INBUFSIZ);
  239.         incnt -= offset;
  240.         inptr = inbuf + offset;
  241.     }
  242. }
  243.  
  244. /* ---------------------------------------------------------- */
  245.  
  246. void extract_member()
  247. {
  248.         UWORD     b;
  249. /* for test reasons */
  250.  
  251.     bits_left = 0;
  252.     bitbuf = 0;
  253.     outpos = 0L;
  254.     outcnt = 0;
  255.     outptr = outbuf;
  256.     zipeof = 0;
  257.     crc32val = 0xFFFFFFFFL;
  258.  
  259.     zmemset(outbuf, 0, OUTBUFSIZ);
  260.     if (aflag)                          /* if we have scratchpad.. v2.0g */
  261.         zmemset(outout, 0, OUTBUFSIZ);  /* ..clear it out v2.0g */
  262.       
  263.     if (tflag)
  264.         fprintf(stderr, "Testing: %-12s ", filename);
  265.     else {
  266.         if(!mapped_name())    /* member name conversion failed  v2.0j */
  267.         exit(1);        /* choke and die v2.0j */
  268.  
  269.         /* create the output file with READ and WRITE permissions */
  270.         if (create_output_file())
  271.             return; /* was exit(1); */
  272.     }
  273.     switch (lrec.compression_method) {
  274.  
  275.     case 0: {   /* stored */
  276.             if (!tflag)
  277.                 fprintf(stderr, " Extracting: %-12s ", filename);
  278.             if (cflag) fprintf(stderr, "\n");
  279.             while (ReadByte(&b))
  280.                 OUTB(b);
  281.         }
  282.         break;
  283.  
  284.     case 1: {       /* shrunk */
  285.             if (!tflag)
  286.                 fprintf(stderr, "UnShrinking: %-12s ", filename);
  287.             if (cflag) fprintf(stderr, "\n");
  288.             unShrink();
  289.         }
  290.         break;
  291.  
  292.     case 2:
  293.     case 3:
  294.     case 4:
  295.     case 5: {
  296.             if (!tflag)
  297.                 fprintf(stderr, "  Expanding: %-12s ", filename);
  298.             if (cflag) fprintf(stderr, "\n");
  299.             unReduce();
  300.         }
  301.         break;
  302.  
  303.     case 6: {
  304.             if (!tflag)
  305.                 fprintf(stderr, "  Exploding: %-12s ", filename);
  306.             if (cflag) fprintf(stderr, "\n");
  307.             unImplode();
  308.         }
  309.         break;
  310.  
  311.     default:
  312.         fprintf(stderr, "Unknown compression method.");
  313.     }
  314.  
  315.     /* write the last partial buffer, if any */
  316.     FlushOutput ();
  317.  
  318.     if (!tflag)  {
  319. #ifndef UNIX
  320.         /* set output file date and time */
  321.         set_file_time();
  322.         close(outfd);
  323. #else
  324.         close(outfd);
  325.         /* set output file date and time */
  326.         set_file_time();
  327. #endif
  328.     }
  329.  
  330.     crc32val = ~crc32val;
  331. #ifdef NOTINT16     /* v2.0c */
  332.     if (crc32val != lrec.crc32)
  333.         fprintf(stderr, " Bad CRC %08lx  (should be %08lx)", crc32val,
  334.             lrec.crc32);
  335. #else   /* !NOTINT16 */
  336.     if (crc32val != LONGI(lrec.crc32))
  337.         fprintf(stderr, " Bad CRC %08lx  (should be %08lx)", crc32val,
  338.             LONGI(lrec.crc32));
  339. #endif  /* NOTINT16 */
  340.  
  341.     else if (tflag)
  342.         fprintf(stderr, " OK");
  343.  
  344.     fprintf(stderr, "\n");
  345. }
  346.  
  347.  
  348. /* ---------------------------------------------------------- */
  349.  
  350. void get_string(len, s)
  351. int len;
  352. char *s;
  353. {
  354.     readbuf(zipfd, s, len);
  355.     s[len] = 0;
  356.  
  357. #ifdef EBCDIC           /* translate the filename to ebcdic */
  358.     a_to_e( s );        /* A.B.  03/21/90                   */
  359. #endif
  360. }
  361.  
  362.  
  363. /* ---------------------------------------------------------- */
  364.  
  365. void process_local_file_header(fnamev)
  366. char **fnamev;
  367. {
  368.     int extracted;
  369. #ifdef NOTINT16     /* v2.0c */
  370.     local_byte_header brec;
  371. #endif
  372.  
  373. #ifndef NOTINT16    /* v2.0c */
  374.     readbuf(zipfd, (char *) &lrec, sizeof(lrec));   /* v2.0b */
  375. #else   /* NOTINT16 */
  376.     readbuf(zipfd, (char *) &brec, sizeof(brec));
  377.  
  378.     lrec.version_needed_to_extract =
  379.         makeword(brec.version_needed_to_extract);
  380.     lrec.general_purpose_bit_flag =
  381.         makeword(brec.general_purpose_bit_flag);
  382.     lrec.compression_method =
  383.         makeword(brec.compression_method);
  384.     lrec.last_mod_file_time =
  385.         makeword(brec.last_mod_file_time);
  386.     lrec.last_mod_file_date =
  387.         makeword(brec.last_mod_file_date);
  388.     lrec.crc32 =
  389.         makelong(brec.crc32);
  390.     lrec.compressed_size =
  391.         makelong(brec.compressed_size);
  392.     lrec.uncompressed_size =
  393.         makelong(brec.uncompressed_size);
  394.     lrec.filename_length =
  395.         makeword(brec.filename_length);
  396.     lrec.extra_field_length =
  397.         makeword(brec.extra_field_length);
  398. #endif  /* NOTINT16 */
  399.  
  400. #ifdef HIGH_LOW
  401.     swap_bytes(&lrec.filename_length);
  402.     swap_bytes(&lrec.extra_field_length);
  403.     swap_lbytes(LONGIP(lrec.compressed_size));
  404.     swap_lbytes(LONGIP(lrec.uncompressed_size));
  405.     swap_bytes(&lrec.compression_method);
  406.     swap_bytes(&lrec.version_needed_to_extract);
  407.     swap_bytes(&lrec.general_purpose_bit_flag);
  408.     swap_bytes(&lrec.last_mod_file_time);
  409.     swap_bytes(&lrec.last_mod_file_date);
  410.     swap_lbytes(LONGIP(lrec.crc32));
  411. #endif  /* HIGH_LOW */
  412.  
  413. #ifdef NOTINT16     /* v2.0c */
  414.     csize = lrec.compressed_size;
  415.     ucsize = lrec.uncompressed_size;
  416. #else   /* !NOTINT16 */
  417.     csize = LONGI(lrec.compressed_size);
  418.     ucsize = LONGI(lrec.uncompressed_size);
  419. #endif  /* NOTINT16 */
  420.  
  421.     get_string(lrec.filename_length, filename);
  422.     get_string(lrec.extra_field_length, extra);
  423.  
  424.     extracted = 0;
  425.     for (--fnamev; *++fnamev; )  {
  426.         if (match(filename, *fnamev))  {
  427.             if (vflag)
  428.                 dir_member();
  429.             else  {
  430.                 extract_member();
  431.                 extracted = 1;
  432.             }
  433.             break;
  434.         }
  435.     }
  436.     if (!extracted)
  437.         skip_member();
  438. }
  439.  
  440.  
  441. /* ---------------------------------------------------------- */
  442.  
  443. void process_central_file_header()
  444. {
  445.     central_directory_file_header rec;
  446.     char filename[STRSIZ];
  447.     char extra[STRSIZ];
  448. /*  char comment[STRSIZ]; v2.0b using global comment so we can display it */
  449.  
  450. #ifdef NOTINT16     /* v2.0c */
  451.     central_directory_byte_header byterec;
  452. #endif
  453.  
  454. #ifndef NOTINT16    /* v2.0c */
  455.     readbuf(zipfd, (char *) &rec, sizeof(rec)); /* v2.0b */
  456. #else   /* NOTINT16 */
  457.     readbuf(zipfd, (char *) &byterec, sizeof(byterec) );        /* v2.0c */
  458.  
  459.     rec.version_made_by =
  460.         makeword(byterec.version_made_by);
  461.     rec.version_needed_to_extract =
  462.         makeword(byterec.version_needed_to_extract);
  463.     rec.general_purpose_bit_flag =
  464.         makeword(byterec.general_purpose_bit_flag);
  465.     rec.compression_method =
  466.         makeword(byterec.compression_method);
  467.     rec.last_mod_file_time =
  468.         makeword(byterec.last_mod_file_time);
  469.     rec.last_mod_file_date =
  470.         makeword(byterec.last_mod_file_date);
  471.     rec.crc32 =
  472.         makelong(byterec.crc32);
  473.     rec.compressed_size =
  474.         makelong(byterec.compressed_size);
  475.     rec.uncompressed_size =
  476.         makelong(byterec.uncompressed_size);
  477.     rec.filename_length =
  478.         makeword(byterec.filename_length);
  479.     rec.extra_field_length =
  480.         makeword(byterec.extra_field_length);
  481.     rec.file_comment_length =
  482.         makeword(byterec.file_comment_length);
  483.     rec.disk_number_start =
  484.         makeword(byterec.disk_number_start);
  485.     rec.internal_file_attributes =
  486.         makeword(byterec.internal_file_attributes);
  487.     rec.external_file_attributes =
  488.         makeword(byterec.external_file_attributes);
  489.     rec.relative_offset_local_header =
  490.         makelong(byterec.relative_offset_local_header);
  491. #endif  /* NOTINT16 */
  492.  
  493. #ifdef HIGH_LOW
  494.     swap_bytes(&rec.filename_length);
  495.     swap_bytes(&rec.extra_field_length);
  496.     swap_bytes(&rec.file_comment_length);
  497. #endif
  498.  
  499.     get_string(rec.filename_length, filename);
  500.     get_string(rec.extra_field_length, extra);
  501.     get_string(rec.file_comment_length, comment);
  502. }
  503.  
  504.  
  505. /* ---------------------------------------------------------- */
  506.  
  507. void process_end_central_dir()
  508. {
  509.     end_central_dir_record rec;
  510. /*  char comment[STRSIZ]; v2.0b made global */
  511.  
  512. #ifdef NOTINT16     /* v2.0c */
  513.     end_central_byte_record byterec;
  514. #endif
  515.  
  516. #ifndef NOTINT16    /* v2.0c */
  517.     readbuf(zipfd, (char *) &rec, sizeof(rec)); /* v2.0b */
  518. #else   /* NOTINT16 */
  519.     readbuf(zipfd, (char *) &byterec, sizeof(byterec) );
  520.  
  521.     rec.number_this_disk =
  522.         makeword(byterec.number_this_disk);
  523.     rec.number_disk_with_start_central_directory =
  524.         makeword(byterec.number_disk_with_start_central_directory);
  525.     rec.total_entries_central_dir_on_this_disk =
  526.         makeword(byterec.total_entries_central_dir_on_this_disk);
  527.     rec.total_entries_central_dir =
  528.         makeword(byterec.total_entries_central_dir);
  529.     rec.size_central_directory =
  530.         makelong(byterec.size_central_directory);
  531.     rec.offset_start_central_directory =
  532.         makelong(byterec.offset_start_central_directory);
  533.     rec.zipfile_comment_length =
  534.         makeword(byterec.zipfile_comment_length);
  535. #endif  /* NOTINT16 */
  536.  
  537. #ifdef HIGH_LOW
  538.     swap_bytes(&rec.zipfile_comment_length);
  539. #endif
  540.  
  541.     /* There seems to be no limit to the zipfile
  542.        comment length.  Some zipfiles have comments
  543.        longer than 256 bytes.  Currently no use is
  544.        made of the comment anyway.
  545.      */
  546. /* #if 0
  547.  * v2.0b Enabling comment display
  548.  */
  549.     get_string(rec.zipfile_comment_length, comment);
  550. /* #endif */
  551. }
  552.  
  553.  
  554. /* ---------------------------------------------------------- */
  555.  
  556. void process_headers()
  557. {
  558.     int ratio;
  559.     long sig;
  560.  
  561. #ifdef NOTINT16     /* v2.0c */
  562.     byte sigbyte[4];
  563. #endif
  564.  
  565.     if (vflag)  {
  566.         members = 0;
  567.         tot_ucsize = tot_csize = 0;
  568.         printf("\n Length  Method   Size  Ratio   Date    Time   \
  569. CRC-32    Name\n ------  ------   ----- -----   ----    ----   ------    \
  570. ----\n");
  571.     }
  572.  
  573.     while (1) {
  574. #ifdef NOTINT16     /* v2.0c */
  575.     if (readbuf(zipfd, (char *) sigbyte, 4) != 4)
  576. #else   /* !NOTINT16 */
  577.     if (readbuf(zipfd, (char *) &sig, sizeof(sig)) != sizeof(sig))
  578. #endif  /* NOTINT16 */
  579.         return;
  580.  
  581. #ifdef NOTINT16     /* v2.0c */
  582.         sig = makelong(sigbyte);
  583. #endif
  584.  
  585. #ifdef HIGH_LOW
  586.         swap_lbytes(&sig);
  587. #endif
  588.  
  589.         if (sig == LOCAL_FILE_HEADER_SIGNATURE)
  590.             process_local_file_header(fnv);
  591.         else if (sig == CENTRAL_FILE_HEADER_SIGNATURE)
  592.             process_central_file_header();
  593.         else if (sig == END_CENTRAL_DIR_SIGNATURE) {
  594.             process_end_central_dir();
  595.             break;
  596.         }
  597.         else {
  598.             fprintf(stderr, "Invalid Zipfile Header\n");
  599.             return;
  600.         }
  601.     }
  602.     if (vflag)  {
  603.         if (tot_ucsize != 0)  {
  604.             ratio = (int) ((1000L * (tot_ucsize-tot_csize))
  605.                     / tot_ucsize);
  606.             if ((ratio % 10) >= 5)
  607.                 ratio += 10;
  608.         }
  609.         else
  610.             ratio = 0;
  611.         printf(" ------          ------  \
  612. ---                             -------\n\
  613. %7ld         %7ld %3d%%                             %7d\n",
  614.         tot_ucsize, tot_csize, ratio / 10, members);
  615.  
  616.         if( comment[0] )                /* v2.0b */
  617.             printf("%s\n",comment);     /* v2.0b */
  618.     }
  619. }
  620.  
  621.  
  622. /* ---------------------------------------------------------- */
  623. /* v3.04 Patch to enable processing of self-extracting ".EXE"
  624.  * (and other) files that might have weird junk before the first
  625.  * actual file member.
  626.  * I don't THINK anyone'll have problems with this .. but just in case,
  627.  * you can disable the entire mess by enabling the "NOSKIP" ifdef.
  628.  * (up near code top).
  629.  * Thanks to Warner Losh for this patch.
  630.  */
  631. #ifndef NOSKIP
  632. void skip_to_signature()
  633. {
  634.     static char pk[] = "PK";
  635.     int i, nread;
  636.     unsigned char ch;
  637.     extern int errno;
  638.     
  639.     errno = 0;            /* Be sure we start with 0 */
  640.     do {
  641.         /*
  642.          * Search for "PK"
  643.          */
  644.         i = 0;
  645.         while ((nread = read (zipfd, &ch, 1)) && i < 2) {
  646.             if (ch == pk[i]) {
  647.                 i++;
  648.             }
  649.             else {
  650.                 if (ch == pk[0])
  651.                     i = 1;
  652.                 else
  653.                     i = 0;
  654.             }
  655.         }
  656.     if (errno || nread==0) {    /* read err or EOF */
  657.         fprintf(stderr, "Unable to find a valid header signature. Aborting.\n");
  658.         exit (2);
  659.     }
  660.     } while (ch > 20);
  661.  
  662.     /*
  663.      * We have now read 3 characters too many, so we backup.
  664.      */
  665.     lseek (zipfd, -3L, SEEK_CUR);
  666. }
  667. #endif        /* NOSKIP */
  668.  
  669.  
  670. void process_zipfile()
  671. {
  672.     /*
  673.      * open the zipfile for reading and in BINARY mode to prevent cr/lf
  674.      * translation, which would corrupt the bitstreams
  675.      */
  676.  
  677.     if (open_input_file())
  678.         exit(1);
  679.  
  680. #ifndef NOSKIP        /* v3.03 */
  681.     skip_to_signature();    /* read up to first "PK%" v3.03 */
  682. #endif
  683.     process_headers();
  684.  
  685.     close(zipfd);
  686. }
  687.  
  688. /* ---------------------------------------------------------- */
  689.  
  690. void usage()        /* v2.0j */
  691. {
  692.  
  693. #ifdef EBCDIC                              /* A.B. 03/20/90   */
  694.   char *astring = "-a  ascii to ebcdic conversion";
  695. #else
  696.   char *astring = "-a  convert to unix textfile format (CR LF => LF)";    /* v3.04 */
  697. #endif
  698.  
  699. fprintf(stderr, "\n%s\nCourtesy of:  S.H.Smith  and  The Tool Shop BBS,  (602) 279-2673.\n\n",VERSION);
  700. fprintf(stderr, "Usage:  unzip [-tcamv] file[.zip] [filespec...]\n\
  701.   -t  test member files\n\
  702.   -c  output to stdout\n\
  703.   %s\n\
  704.   -m  map extracted filenames to lowercase\n\
  705.   -v  view directory\n",astring);
  706.     exit(1);
  707. }
  708.  
  709. /* ---------------------------------------------------------- */
  710.  
  711. /*
  712.  * main program
  713.  *
  714.  */
  715.  
  716. void main(argc, argv)
  717. int argc;
  718. char **argv;
  719. {
  720.     char *s;
  721.     int c;
  722.     struct stat statbuf;        /* v3.03 */
  723.     
  724. #ifdef DEBUG_STRUC                      /* v2.0e */
  725. printf("local_file_header size: %X\n",
  726.     sizeof(struct local_file_header) );
  727. printf("local_byte_header size: %X\n",
  728.     sizeof(struct local_byte_header) );
  729.  
  730. printf("central directory header size: %X\n",
  731.     sizeof(struct central_directory_file_header) );
  732. printf("central directory byte header size: %X\n",
  733.     sizeof(struct central_directory_byte_header) );
  734.  
  735. printf("end central dir record size: %X\n",
  736.     sizeof(struct end_central_dir_record) );
  737. printf("end central dir byte record size: %X\n",
  738.     sizeof(struct end_central_byte_record) );
  739. #endif
  740.  
  741.     while (--argc > 0 && (*++argv)[0] == '-')  {
  742.         s = argv[0] + 1;
  743. #ifndef __TURBOC__
  744.         while (c = *s++)  {
  745. #else
  746.         while ((c = *s++) != '\0') {      /* v2.0b */
  747. #endif
  748.  
  749. /* Something is SERIOUSLY wrong with my host's tolower() function! */
  750. /* #ifndef BSD */
  751. /*            switch (tolower(c))  { */
  752. /* #else */
  753.             switch(c) {
  754. /* #endif */
  755.             case ('T'):
  756.             case ('t'):
  757.                 ++tflag;
  758.                 break;
  759.             case ('V'):
  760.             case ('v'):
  761.                 ++vflag;
  762.                 break;
  763.             case ('C'):
  764.             case ('c'):
  765.                 ++cflag;
  766. #ifdef EBCDIC
  767.                 ++aflag;       /* This is so you can read it on the screen */
  768. #endif                         /*  A.B.  03/24/90                          */
  769.                 break;
  770.             case ('A'):
  771.             case ('a'):
  772.                 ++aflag;
  773.                 break;
  774.         case ('M'):        /* map filename flag v2.0j */
  775.         case ('m'):
  776.         ++mflag;
  777.         break;
  778.             default:
  779.                 usage();
  780.                 break;
  781.             }
  782.         }
  783.     }
  784. /*  I removed the filter for the a and c flags so they could be used together */
  785. /*  Especially on EBCDIC based systems where you would want to read the text  */
  786. /*  on the screen.  Allan Bjorklund.  03/24/90                                */
  787.  
  788.     if ((tflag && vflag) || (tflag && cflag) || (vflag && cflag) ||
  789.         (tflag && aflag) || (aflag && vflag))
  790.  
  791.     {
  792.         fprintf(stderr, "only one of -t, -c, -a, or -v\n");
  793.         exit(1);
  794.     }
  795.     if (argc-- == 0)
  796.         usage();
  797.  
  798.     /* .ZIP default if none provided by user */
  799.     strcpy(zipfn, *argv++);
  800. /* v2.0b This doesn't permit paths like "..\dir\filename" */
  801.  
  802. #ifdef REALOLDSTUFF        /* v3.02 */
  803. #ifdef OLDSTUF
  804.     if (strchr(zipfn, '.') == NULL)
  805.         strcat(zipfn, ZSUFX);
  806. #else    /* v2.0b New code */
  807.  
  808.     c = strlen(zipfn);
  809.     if ( (c < 5)                             /* less than x.zip */
  810.       || (strcmp (&zipfn[c-4], ZSUFX) != 0)) /* v2.0b type doesn't
  811.                                               * match */
  812.         strcat (zipfn, ZSUFX);
  813. #endif
  814. #else                /* v3.02 */
  815.       /*
  816.        * OK, first check to see if the name is as given.  If it is
  817.        * found as given, then we don't need to bother adding the
  818.        * ZSUFX.  If it isn't found, then add the ZSUFX.  We don't
  819.        * check to see if this results in a good name, but that check
  820.        * will be done later.
  821.        */
  822.     if(stat (zipfn, &statbuf))        /* v3.02 */
  823.         strcat (zipfn, ZSUFX);        /* v3.02 */
  824.  
  825. #endif    /* not REALOLDSTUF */
  826.       
  827.     /* if any member file specs on command line, set filename
  828.        pointer to point to them. */
  829.  
  830.     if (argc != 0)
  831.         fnv = argv;
  832.  
  833.         /* allocate i/o buffers */
  834.     inbuf = (byte *) (malloc(INBUFSIZ));
  835.     outbuf = (byte *) (malloc(OUTBUFSIZ));
  836.  
  837.     /* v2.0g Hacked Allan's code.  No need allocating an ascebc
  838.      * scratch buffer unless we're doing translation.
  839.      */
  840.  
  841.     if(aflag)                           /* we need an ascebc scratch v2.0g */
  842.         outout = (byte *) (malloc(OUTBUFSIZ)); /* ..so allocate it v2.0g */
  843.     else
  844.         outout = outbuf;                /* just point to outbuf v2.0g */
  845.  
  846.     if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL)) {  /* v2.0g */
  847.         fprintf(stderr, "Can't allocate buffers!\n");
  848.         exit(1);
  849.     }
  850.  
  851.     /* do the job... */
  852.     process_zipfile();
  853.     exit(0);
  854. }
  855.  
  856.