home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip51.zip / extract.c < prev    next >
C/C++ Source or Header  |  1994-01-27  |  37KB  |  932 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   extract.c
  4.  
  5.   This file contains the high-level routines ("driver routines") for extrac-
  6.   ting and testing zipfile members.  It calls the low-level routines in files
  7.   explode.c, inflate.c, unreduce.c and unshrink.c.
  8.  
  9.   ---------------------------------------------------------------------------*/
  10.  
  11.  
  12. #include "unzip.h"
  13. #include "crypt.h"
  14. #ifdef MSWIN
  15. #  include "wizunzip.h"
  16. #  include "replace.h"
  17. #endif
  18.  
  19. int newfile;   /* used also in file_io.c (flush()) */
  20.  
  21. static int store_info __((void));
  22. static int extract_or_test_member __((void));
  23.  
  24. static char *VersionMsg =
  25.   "   skipping: %-22s  need %s compat. v%u.%u (can do v%u.%u)\n";
  26. static char *ComprMsg =
  27.   "   skipping: %-22s  compression method %d\n";
  28. static char *FilNamMsg =
  29.   "%s:  bad filename length (%s)\n";
  30. static char *ExtFieldMsg =
  31.   "%s:  bad extra field length (%s)\n";
  32. static char *OffsetMsg =
  33.   "file #%d:  bad zipfile offset (%s):  %ld\n";
  34. static char *ExtractMsg =
  35.   "%11s: %-22s  %s%s";
  36. static char *LengthMsg =
  37.   "%s  %s:  %ld bytes required to uncompress to %lu bytes;\n       %s\
  38.    supposed to require %lu bytes%s%s%s\n";
  39.  
  40.  
  41.  
  42.  
  43.  
  44. /**************************************/
  45. /*  Function extract_or_test_files()  */
  46. /**************************************/
  47.  
  48. int extract_or_test_files()    /* return PK-type error code */
  49. {
  50.     uch *cd_inptr;
  51.     int cd_incnt, error, error_in_archive=PK_COOL;
  52.     int i, j, renamed, query, len, filnum=(-1), blknum=0;
  53.     int *fn_matched=NULL, *xn_matched=NULL;
  54.     ush members_remaining, num_skipped=0, num_bad_pwd=0;
  55.     long cd_bufstart, bufstart, inbuf_offset, request;
  56.     static min_info info[DIR_BLKSIZ];
  57.  
  58.  
  59. /*---------------------------------------------------------------------------
  60.     The basic idea of this function is as follows.  Since the central di-
  61.     rectory lies at the end of the zipfile and the member files lie at the
  62.     beginning or middle or wherever, it is not very desirable to simply
  63.     read a central directory entry, jump to the member and extract it, and
  64.     then jump back to the central directory.  In the case of a large zipfile
  65.     this would lead to a whole lot of disk-grinding, especially if each mem-
  66.     ber file is small.  Instead, we read from the central directory the per-
  67.     tinent information for a block of files, then go extract/test the whole
  68.     block.  Thus this routine contains two small(er) loops within a very
  69.     large outer loop:  the first of the small ones reads a block of files
  70.     from the central directory; the second extracts or tests each file; and
  71.     the outer one loops over blocks.  There's some file-pointer positioning
  72.     stuff in between, but that's about it.  Btw, it's because of this jump-
  73.     ing around that we can afford to be lenient if an error occurs in one of
  74.     the member files:  we should still be able to go find the other members,
  75.     since we know the offset of each from the beginning of the zipfile.
  76.  
  77.     Begin main loop over blocks of member files.  We know the entire central
  78.     directory is on this disk:  we would not have any of this information un-
  79.     less the end-of-central-directory record was on this disk, and we would
  80.     not have gotten to this routine unless this is also the disk on which
  81.     the central directory starts.  In practice, this had better be the ONLY
  82.     disk in the archive, but maybe someday we'll add multi-disk support.
  83.   ---------------------------------------------------------------------------*/
  84.  
  85.     pInfo = info;
  86.     members_remaining = ecrec.total_entries_central_dir;
  87. #ifdef CRYPT
  88.     newzip = TRUE;
  89. #endif
  90.  
  91.     /* malloc space for check on unmatched filespecs (OK if one or both NULL) */
  92.     if (filespecs > 0  &&
  93.         (fn_matched=(int *)malloc(filespecs*sizeof(int))) != NULL)
  94.         for (i = 0;  i < filespecs;  ++i)
  95.             fn_matched[i] = FALSE;
  96.     if (xfilespecs > 0  &&
  97.         (xn_matched=(int *)malloc(xfilespecs*sizeof(int))) != NULL)
  98.         for (i = 0;  i < xfilespecs;  ++i)
  99.             xn_matched[i] = FALSE;
  100.  
  101.     while (members_remaining) {
  102.         j = 0;
  103.  
  104.         /*
  105.          * Loop through files in central directory, storing offsets, file
  106.          * attributes, case-conversion and text-conversion flags until block
  107.          * size is reached.
  108.          */
  109.  
  110.         while (members_remaining && (j < DIR_BLKSIZ)) {
  111.             --members_remaining;
  112.             pInfo = &info[j];
  113.  
  114.             if (readbuf(sig, 4) <= 0) {
  115.                 error_in_archive = PK_EOF;
  116.                 members_remaining = 0;  /* ...so no more left to do */
  117.                 break;
  118.             }
  119.             if (strncmp(sig, central_hdr_sig, 4)) {  /* just to make sure */
  120.                 fprintf(stderr, CentSigMsg, j);  /* sig not found */
  121.                 fprintf(stderr, ReportMsg);   /* check binary transfers */
  122.                 error_in_archive = PK_BADERR;
  123.                 members_remaining = 0;  /* ...so no more left to do */
  124.                 break;
  125.             }
  126.             /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
  127.             if ((error = process_cdir_file_hdr()) != PK_COOL) {
  128.                 error_in_archive = error;   /* only PK_EOF defined */
  129.                 members_remaining = 0;  /* ...so no more left to do */
  130.                 break;
  131.             }
  132.             if ((error = do_string(crec.filename_length,FILENAME)) != PK_COOL) {
  133.                 if (error > error_in_archive)
  134.                     error_in_archive = error;
  135.                 if (error > PK_WARN) {  /* fatal:  no more left to do */
  136.                     fprintf(stderr, FilNamMsg, filename, "central");
  137.                     members_remaining = 0;
  138.                     break;
  139.                 }
  140.             }
  141.             if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0)
  142.             {
  143.                 if (error > error_in_archive)
  144.                     error_in_archive = error;
  145.                 if (error > PK_WARN) {  /* fatal */
  146.                     fprintf(stderr, ExtFieldMsg, filename, "central");
  147.                     members_remaining = 0;
  148.                     break;
  149.                 }
  150.             }
  151.             if ((error = do_string(crec.file_comment_length,SKIP)) != PK_COOL) {
  152.                 if (error > error_in_archive)
  153.                     error_in_archive = error;
  154.                 if (error > PK_WARN) {  /* fatal */
  155.                     fprintf(stderr, "\n%s:  bad file comment length\n",
  156.                             filename);
  157.                     members_remaining = 0;
  158.                     break;
  159.                 }
  160.             }
  161.             if (process_all_files) {
  162.                 if (store_info())
  163.                     ++j;  /* file is OK; info[] stored; continue with next */
  164.                 else
  165.                     ++num_skipped;
  166.             } else {
  167.                 int   do_this_file = FALSE;
  168.                 char  **pfn = pfnames-1;
  169.  
  170.                 while (*++pfn)
  171.                     if (match(filename, *pfn, pInfo->lcflag)) {
  172.                         do_this_file = TRUE;
  173.                         if (fn_matched)
  174.                             fn_matched[pfn-pfnames] = TRUE;
  175.                         break;       /* found match, so stop looping */
  176.                     }
  177.                 if (do_this_file) {  /* check if this is an excluded file */
  178.                     char  **pxn = pxnames-1;
  179.  
  180.                     while (*++pxn)
  181.                         if (match(filename, *pxn, pInfo->lcflag)) {
  182.                             do_this_file = FALSE;
  183.                             if (xn_matched)
  184.                                 xn_matched[pxn-pxnames] = TRUE;
  185.                             break;
  186.                         }
  187.                 }
  188.                 if (do_this_file)
  189.                     if (store_info())
  190.                         ++j;            /* file is OK */
  191.                     else
  192.                         ++num_skipped;  /* unsupp. compression or encryption */
  193.             } /* end if (process_all_files) */
  194.  
  195.  
  196.         } /* end while-loop (adding files to current block) */
  197.  
  198.         /* save position in central directory so can come back later */
  199.         cd_bufstart = cur_zipfile_bufstart;
  200.         cd_inptr = inptr;
  201.         cd_incnt = incnt;
  202.  
  203.     /*-----------------------------------------------------------------------
  204.         Second loop:  process files in current block, extracting or testing
  205.         each one.
  206.       -----------------------------------------------------------------------*/
  207.  
  208.         for (i = 0; i < j; ++i) {
  209.             filnum = i + blknum*DIR_BLKSIZ;
  210.             pInfo = &info[i];
  211.  
  212.             /* if the target position is not within the current input buffer
  213.              * (either haven't yet read far enough, or (maybe) skipping back-
  214.              * ward), skip to the target position and reset readbuf(). */
  215.  
  216.             /* LSEEK(pInfo->offset):  */
  217.             request = pInfo->offset + extra_bytes;
  218.             inbuf_offset = request % INBUFSIZ;
  219.             bufstart = request - inbuf_offset;
  220.  
  221.             if (request < 0) {
  222.                 fprintf(stderr, SeekMsg, zipfn, ReportMsg);
  223.                 error_in_archive = PK_BADERR;
  224.                 continue;   /* but can still go on */
  225.             } else if (bufstart != cur_zipfile_bufstart) {
  226.                 cur_zipfile_bufstart = lseek(zipfd,(LONGINT)bufstart,SEEK_SET);
  227.                 if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0) {
  228.                     fprintf(stderr, OffsetMsg, filnum, "lseek", bufstart);
  229.                     error_in_archive = PK_BADERR;
  230.                     continue;   /* can still do next file */
  231.                 }
  232.                 inptr = inbuf + (int)inbuf_offset;
  233.                 incnt -= (int)inbuf_offset;
  234.             } else {
  235.                 incnt += (inptr-inbuf) - (int)inbuf_offset;
  236.                 inptr = inbuf + (int)inbuf_offset;
  237.             }
  238.  
  239.             /* should be in proper position now, so check for sig */
  240.             if (readbuf(sig, 4) <= 0) {  /* bad offset */
  241.                 fprintf(stderr, OffsetMsg, filnum, "EOF", request);
  242.                 error_in_archive = PK_BADERR;
  243.                 continue;   /* but can still try next one */
  244.             }
  245.             if (strncmp(sig, local_hdr_sig, 4)) {
  246.                 fprintf(stderr, OffsetMsg, filnum, "local header sig", request);
  247.                 error_in_archive = PK_ERR;
  248. /* GRR testing */
  249.                 if (filnum == 0) {
  250.                     fprintf(stderr, "  (attempting to re-compensate)\n");
  251.                     extra_bytes = 0L;
  252.                     LSEEK(pInfo->offset)
  253.                     if (readbuf(sig, 4) <= 0) {  /* bad offset */
  254.                         fprintf(stderr, OffsetMsg, filnum, "EOF", request);
  255.                         error_in_archive = PK_BADERR;
  256.                         continue;   /* but can still try next one */
  257.                     }
  258.                     if (strncmp(sig, local_hdr_sig, 4)) {
  259.                         fprintf(stderr, OffsetMsg, filnum, "local header sig",
  260.                           request);
  261.                         error_in_archive = PK_BADERR;
  262.                         continue;
  263.                     }
  264.                 }
  265. /* GRR testing */
  266.             }
  267.             if ((error = process_local_file_hdr()) != PK_COOL) {
  268.                 fprintf(stderr, "\nfile #%d:  bad local header\n", filnum);
  269.                 error_in_archive = error;   /* only PK_EOF defined */
  270.                 continue;   /* can still try next one */
  271.             }
  272.             if ((error = do_string(lrec.filename_length,FILENAME)) != PK_COOL) {
  273.                 if (error > error_in_archive)
  274.                     error_in_archive = error;
  275.                 if (error > PK_WARN) {
  276.                     fprintf(stderr, FilNamMsg, filename, "local");
  277.                     continue;   /* go on to next one */
  278.                 }
  279.             }
  280.             if (extra_field != (uch *)NULL) {
  281.                 free(extra_field);
  282.                 extra_field = (uch *)NULL;
  283.             }
  284.             if ((error = do_string(lrec.extra_field_length,EXTRA_FIELD)) != 0) {
  285.                 if (error > error_in_archive)
  286.                     error_in_archive = error;
  287.                 if (error > PK_WARN) {
  288.                     fprintf(stderr, ExtFieldMsg, filename, "local");
  289.                     continue;   /* go on */
  290.                 }
  291.             }
  292.  
  293.             /*
  294.              * just about to extract file:  if extracting to disk, check if
  295.              * already exists, and if so, take appropriate action according to
  296.              * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
  297.              * loop because we don't store the possibly renamed filename[] in
  298.              * info[])
  299.              */
  300.             if (!tflag && !cflag) {
  301.                 renamed = FALSE;   /* user hasn't renamed output file yet */
  302.  
  303. startover:
  304.                 query = FALSE;
  305. #ifdef MACOS
  306.                 macflag = (pInfo->hostnum == MAC_);
  307. #endif
  308.                 /* mapname can create dirs if not freshening or if renamed */
  309.                 if ((error = mapname(renamed)) > PK_WARN) {
  310.                     if (error == IZ_CREATED_DIR) {
  311.  
  312.                         /* GRR:  add code to set times/attribs on dirs--
  313.                          * save to list, sort when done (a la zip), set
  314.                          * times/attributes on deepest dirs first */
  315.  
  316.                     } else if (error == IZ_VOL_LABEL) {
  317.                         fprintf(stderr,
  318.                           "   skipping: %-22s  %svolume label\n", filename,
  319. #ifdef DOS_NT_OS2
  320.                           volflag? "hard disk " :
  321. #endif
  322.                           "");
  323.                     /*  if (!error_in_archive)
  324.                             error_in_archive = PK_WARN;  */
  325.                     } else if (error > PK_ERR  &&  error_in_archive < PK_ERR)
  326.                         error_in_archive = PK_ERR;
  327.                     Trace((stderr, "mapname(%s) returns error = %d\n", filename,
  328.                       error));
  329.                     continue;   /* go on to next file */
  330.                 }
  331.  
  332.                 switch (check_for_newer(filename)) {
  333.                     case DOES_NOT_EXIST:
  334.                         if (fflag && !renamed)  /* don't skip if just renamed */
  335.                             continue;   /* freshen (no new files):  skip */
  336.                         break;
  337.                     case EXISTS_AND_OLDER:
  338.                         if (overwrite_none)
  339.                             continue;   /* never overwrite:  skip file */
  340.                         if (!overwrite_all && !force_flag)
  341.                             query = TRUE;
  342.                         break;
  343.                     case EXISTS_AND_NEWER:             /* (or equal) */
  344.                         if (overwrite_none || (uflag && !renamed))
  345.                             continue;  /* skip if update/freshen & orig name */
  346.                         if (!overwrite_all && !force_flag)
  347.                             query = TRUE;
  348.                         break;
  349.                 }
  350.                 if (query) {
  351. #ifdef MSWIN
  352.                     FARPROC lpfnprocReplace;
  353.                     int ReplaceDlgRetVal;   /* replace dialog return value */
  354.  
  355.                     ShowCursor(FALSE);      /* turn off cursor */
  356.                     SetCursor(hSaveCursor); /* restore the cursor */
  357.                     lpfnprocReplace = MakeProcInstance(ReplaceProc, hInst);
  358.                     ReplaceDlgRetVal = DialogBoxParam(hInst, "Replace",
  359.                       hWndMain, lpfnprocReplace, (DWORD)(LPSTR)filename);
  360.                     FreeProcInstance(lpfnprocReplace);
  361.                     hSaveCursor = SetCursor(hHourGlass);
  362.                     ShowCursor(TRUE);
  363.                     switch (ReplaceDlgRetVal) {
  364.                         case IDM_REPLACE_RENAME:
  365.                             renamed = TRUE;
  366.                             goto startover;
  367.                         case IDM_REPLACE_YES:
  368.                             break;
  369.                         case IDM_REPLACE_ALL:
  370.                             overwrite_all = TRUE;
  371.                             overwrite_none = FALSE;  /* just to make sure */
  372.                             break;
  373.                         case IDM_REPLACE_NONE:
  374.                             overwrite_none = TRUE;
  375.                             overwrite_all = FALSE;  /* make sure */
  376.                             force_flag = FALSE;     /* ditto */
  377.                             /* FALL THROUGH, skip */
  378.                         case IDM_REPLACE_NO:
  379.                             continue;
  380.                     }
  381. #else /* !MSWIN */
  382. reprompt:
  383.                     fprintf(stderr,
  384.                       "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
  385.                       filename);
  386.                     FFLUSH(stderr);
  387.                     if (fgets(answerbuf, 9, stdin) == NULL) {
  388.                         fprintf(stderr, " NULL\n(assuming [N]one)\n");
  389.                         FFLUSH(stderr);
  390.                         *answerbuf = 'N';
  391.                         if (!error_in_archive)
  392.                             error_in_archive = 1;  /* not extracted:  warning */
  393.                     }
  394.                     switch (*answerbuf) {
  395.                         case 'A':   /* dangerous option:  force caps */
  396.                             overwrite_all = TRUE;
  397.                             overwrite_none = FALSE;  /* just to make sure */
  398.                             break;
  399.                         case 'r':
  400.                         case 'R':
  401.                             do {
  402.                                 fprintf(stderr, "new name: ");
  403.                                 FFLUSH(stderr);
  404.                                 fgets(filename, FILNAMSIZ, stdin);
  405.                                 /* usually get \n here:  better check for it */
  406.                                 len = strlen(filename);
  407.                                 if (filename[len-1] == '\n')
  408.                                     filename[--len] = 0;
  409.                             } while (len == 0);
  410.                             renamed = TRUE;
  411.                             goto startover;   /* sorry for a goto */
  412.                         case 'y':
  413.                         case 'Y':
  414.                             break;
  415.                         case 'N':
  416.                             overwrite_none = TRUE;
  417.                             overwrite_all = FALSE;  /* make sure */
  418.                             force_flag = FALSE;     /* ditto */
  419.                             /* FALL THROUGH, skip */
  420.                         case 'n':
  421.                             continue;   /* skip file */
  422.                         default:
  423.                             fprintf(stderr, "error:  invalid response [%c]\n",
  424.                               *answerbuf);   /* warn the user */
  425.                             goto reprompt;   /* why not another goto? */
  426.                     } /* end switch (*answerbuf) */
  427. #endif /* ?MSWIN */
  428.                 } /* end if (query) */
  429.             } /* end if (extracting to disk) */
  430.  
  431. #ifdef CRYPT
  432.             if (pInfo->encrypted && (error = decrypt()) != PK_COOL) {
  433.                 if (error == PK_MEM2) {
  434.                     if (error > error_in_archive)
  435.                         error_in_archive = error;
  436.                     fprintf(stderr,
  437.                       "   skipping: %-22s  unable to get password\n", filename);
  438.                 } else {  /* (error == PK_WARN) */
  439.                     fprintf(stderr,
  440.                       "   skipping: %-22s  incorrect password\n", filename);
  441.                     ++num_bad_pwd;
  442.                 }
  443.                 continue;   /* go on to next file */
  444.             }
  445. #endif /* CRYPT */
  446.             disk_full = 0;
  447.             if ((error = extract_or_test_member()) != PK_COOL) {
  448.                 if (error > error_in_archive)
  449.                     error_in_archive = error;       /* ...and keep going */
  450.                 if (disk_full > 1)
  451.                     return error_in_archive;        /* (unless disk full) */
  452.             }
  453.         } /* end for-loop (i:  files in current block) */
  454.  
  455.  
  456.         /*
  457.          * Jump back to where we were in the central directory, then go and do
  458.          * the next batch of files.
  459.          */
  460.  
  461.         cur_zipfile_bufstart = lseek(zipfd, (LONGINT)cd_bufstart, SEEK_SET);
  462.         read(zipfd, (char *)inbuf, INBUFSIZ);  /* were there b4 ==> no error */
  463.         inptr = cd_inptr;
  464.         incnt = cd_incnt;
  465.         ++blknum;
  466.  
  467. #ifdef TEST
  468.         printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
  469.         printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
  470.           cur_zipfile_bufstart);
  471.         printf("inptr-inbuf = %d\n", inptr-inbuf);
  472.         printf("incnt = %d\n\n", incnt);
  473. #endif
  474.  
  475.     } /* end while-loop (blocks of files in central directory) */
  476.  
  477. /*---------------------------------------------------------------------------
  478.     Check for unmatched filespecs on command line and print warning if any
  479.     found.
  480.   ---------------------------------------------------------------------------*/
  481.  
  482.     if (fn_matched) {
  483.         for (i = 0;  i < filespecs;  ++i)
  484.             if (!fn_matched[i])
  485.                 fprintf(stderr, "caution: filename not matched:  %s\n",
  486.                   pfnames[i]);
  487.         free(fn_matched);
  488.     }
  489.     if (xn_matched) {
  490.         for (i = 0;  i < xfilespecs;  ++i)
  491.             if (!xn_matched[i])
  492.                 fprintf(stderr, "caution: excluded filename not matched:  %s\n",
  493.                   pxnames[i]);
  494.         free(xn_matched);
  495.     }
  496.  
  497. /*---------------------------------------------------------------------------
  498.     Double-check that we're back at the end-of-central-directory record, and
  499.     print quick summary of results, if we were just testing the archive.  We
  500.     send the summary to stdout so that people doing the testing in the back-
  501.     ground and redirecting to a file can just do a "tail" on the output file.
  502.   ---------------------------------------------------------------------------*/
  503.  
  504.     if (readbuf(sig, 4) <= 0)
  505.         error_in_archive = PK_EOF;
  506.     if (strncmp(sig, end_central_sig, 4)) {     /* just to make sure again */
  507.         fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  508.         fprintf(stderr, ReportMsg);  /* check binary transfers */
  509.         if (!error_in_archive)       /* don't overwrite stronger error */
  510.             error_in_archive = PK_WARN;
  511.     }
  512.     if (tflag) {
  513.         int num=filnum+1 - num_bad_pwd;
  514.  
  515.         if (qflag < 2) {         /* GRR 930710:  was (qflag == 1) */
  516.             if (error_in_archive)
  517.                 printf("At least one %serror was detected in %s.\n",
  518.                   (error_in_archive == 1)? "warning-" : "", zipfn);
  519.             else if (num == 0)
  520.                 printf("Caution:  zero files tested in %s.\n", zipfn);
  521.             else if (process_all_files && (num_skipped+num_bad_pwd == 0))
  522.                 printf("No errors detected in compressed data of %s.\n", zipfn);
  523.             else
  524.                 printf("No errors detected in %s for the %d file%s tested.\n",
  525.                   zipfn, num, (num==1)? "":"s");
  526.             if (num_skipped > 0)
  527.                 printf("%d file%s skipped because of unsupported compression \
  528. or encoding.\n", num_skipped, (num_skipped==1)? "":"s");
  529. #ifdef CRYPT
  530.             if (num_bad_pwd > 0)
  531.                 printf("%d file%s skipped because of incorrect password.\n",
  532.                   num_bad_pwd, (num_bad_pwd==1)? "":"s");
  533. #endif /* CRYPT */
  534.         } else if ((qflag == 0) && !error_in_archive && (num == 0))
  535.             printf("Caution:  zero files tested in %s.\n", zipfn);
  536.     }
  537.  
  538.     /* give warning if files not tested or extracted */
  539.     if ((num_skipped > 0) && !error_in_archive)
  540.         error_in_archive = PK_WARN;
  541. #ifdef CRYPT
  542.     if ((num_bad_pwd > 0) && !error_in_archive)
  543.         error_in_archive = PK_WARN;
  544. #endif /* CRYPT */
  545.  
  546.     return error_in_archive;
  547.  
  548. } /* end function extract_or_test_files() */
  549.  
  550.  
  551.  
  552.  
  553.  
  554. /***************************/
  555. /*  Function store_info()  */
  556. /***************************/
  557.  
  558. static int store_info()   /* return 0 if skipping, 1 if OK */
  559. {
  560. #ifdef SFX
  561. #  define UNKN_COMPR \
  562.    (crec.compression_method!=STORED && crec.compression_method!=DEFLATED)
  563. #else
  564. #  define UNKN_COMPR \
  565.    (crec.compression_method>IMPLODED && crec.compression_method!=DEFLATED)
  566. #endif
  567.  
  568. /*---------------------------------------------------------------------------
  569.     Check central directory info for version/compatibility requirements.
  570.   ---------------------------------------------------------------------------*/
  571.  
  572.     pInfo->encrypted = crec.general_purpose_bit_flag & 1;       /* bit field */
  573.     pInfo->ExtLocHdr = (crec.general_purpose_bit_flag & 8) == 8;/* bit field */
  574.     pInfo->textfile = crec.internal_file_attributes & 1;        /* bit field */
  575.     pInfo->crc = crec.crc32;
  576.     pInfo->compr_size = crec.csize;
  577.  
  578.     switch (aflag) {
  579.         case 0:
  580.             pInfo->textmode = FALSE;   /* bit field */
  581.             break;
  582.         case 1:
  583.             pInfo->textmode = pInfo->textfile;   /* auto-convert mode */
  584.             break;
  585.         default:  /* case 2: */
  586.             pInfo->textmode = TRUE;
  587.             break;
  588.     }
  589.  
  590.     if (crec.version_needed_to_extract[1] == VMS_) {
  591.         if (crec.version_needed_to_extract[0] > VMS_VERSION) {
  592.             fprintf(stderr, VersionMsg, filename, "VMS",
  593.               crec.version_needed_to_extract[0] / 10,
  594.               crec.version_needed_to_extract[0] % 10,
  595.               VMS_VERSION / 10, VMS_VERSION % 10);
  596.             return 0;
  597.         }
  598. #ifndef VMS   /* won't be able to use extra field, but still have data */
  599.         else if (!tflag && !force_flag) {  /* if forcing, extract regardless */
  600.             fprintf(stderr,
  601.               "\n%s:  stored in VMS format.  Extract anyway? (y/n) ",
  602.               filename);
  603.             FFLUSH(stderr);
  604.             fgets(answerbuf, 9, stdin);
  605.             if ((*answerbuf != 'y') && (*answerbuf != 'Y'))
  606.                 return 0;
  607.         }
  608. #endif /* !VMS */
  609.     /* usual file type:  don't need VMS to extract */
  610.     } else if (crec.version_needed_to_extract[0] > UNZIP_VERSION) {
  611.         fprintf(stderr, VersionMsg, filename, "PK",
  612.           crec.version_needed_to_extract[0] / 10,
  613.           crec.version_needed_to_extract[0] % 10,
  614.           UNZIP_VERSION / 10, UNZIP_VERSION % 10);
  615.         return 0;
  616.     }
  617.  
  618.     if UNKN_COMPR {
  619.         fprintf(stderr, ComprMsg, filename, crec.compression_method);
  620.         return 0;
  621.     }
  622. #ifndef CRYPT
  623.     if (pInfo->encrypted) {
  624.         fprintf(stderr, "   skipping: %-22s  encrypted (not supported)\n",
  625.           filename);
  626.         return 0;
  627.     }
  628. #endif /* !CRYPT */
  629.  
  630.     /* map whatever file attributes we have into the local format */
  631.     mapattr();   /* GRR:  worry about return value later */
  632.  
  633.     pInfo->offset = (long) crec.relative_offset_local_header;
  634.     return 1;
  635.  
  636. } /* end function store_info() */
  637.  
  638.  
  639.  
  640.  
  641.  
  642. /***************************************/
  643. /*  Function extract_or_test_member()  */
  644. /***************************************/
  645.  
  646. static int extract_or_test_member()    /* return PK-type error code */
  647. {
  648.     /* GRR 930907:  semi-permanent, at least until auto-conv. bugs are found */
  649.     char *nul="[empty] ", *txt="[text]  ", *bin="[binary]";
  650.     register int b;
  651.     int r, error=PK_COOL;
  652.  
  653.  
  654.  
  655. /*---------------------------------------------------------------------------
  656.     Initialize variables, buffers, etc.
  657.   ---------------------------------------------------------------------------*/
  658.  
  659.     bits_left = 0;     /* unreduce and unshrink only */
  660.     bitbuf = 0L;       /* unreduce and unshrink only */
  661.     zipeof = 0;        /* unreduce and unshrink only */
  662.     newfile = TRUE;
  663.     crc32val = 0xFFFFFFFFL;
  664.  
  665. #ifdef SYMLINKS
  666.     /* if file came from Unix and is a symbolic link and we are extracting
  667.      * to disk, prepare to restore the link */
  668.     if (S_ISLNK(pInfo->file_attr) && (pInfo->hostnum == UNIX_) && !tflag &&
  669.         !cflag && (lrec.ucsize > 0))
  670.         symlnk = TRUE;
  671.     else
  672.         symlnk = FALSE;
  673. #endif /* SYMLINKS */
  674.  
  675.     if (tflag) {
  676.         if (!qflag) {
  677.             fprintf(stdout, ExtractMsg, "testing", filename, "", "");
  678.             fflush(stdout);
  679.         }
  680.     } else {
  681.         if (cflag) {
  682.             outfile = stdout;
  683. #ifdef DOS_NT_OS2
  684.             setmode(fileno(outfile), O_BINARY);
  685. #endif
  686. #ifdef VMS
  687.             if (open_outfile())   /* VMS:  required even for stdout! */
  688.                 return PK_DISK;
  689. #endif
  690.         } else if (open_outfile())
  691.             return PK_DISK;
  692.     }
  693.  
  694. /*---------------------------------------------------------------------------
  695.     Unpack the file.
  696.   ---------------------------------------------------------------------------*/
  697.  
  698.     switch (lrec.compression_method) {
  699.         case STORED:
  700.             if (!tflag && QCOND2) {
  701. #ifdef SYMLINKS
  702.                 if (symlnk)   /* can also be deflated, but rarer... */
  703.                     fprintf(stdout, ExtractMsg, "linking", filename, "", "");
  704.                 else
  705. #endif /* SYMLINKS */
  706.                 fprintf(stdout, ExtractMsg, "extracting", filename,
  707.                   (aflag != 1 /* && pInfo->textfile == pInfo->textmode */ )? ""
  708.                   : (lrec.ucsize == 0L? nul : (pInfo->textfile? txt : bin)),
  709.                   cflag? "\n" : "");
  710.                 fflush(stdout);
  711.             }
  712.             outptr = slide;
  713.             outcnt = 0L;
  714.             while ((b = NEXTBYTE) != EOF && !disk_full) {
  715.                 *outptr++ = (uch)b;
  716.                 if (++outcnt == WSIZE) {
  717.                     flush(slide, outcnt, 0);
  718.                     outptr = slide;
  719.                     outcnt = 0L;
  720.                 }
  721.             }
  722.             if (outcnt)          /* flush final (partial) buffer */
  723.                 flush(slide, outcnt, 0);
  724.             break;
  725.  
  726. #ifndef SFX
  727.         case SHRUNK:
  728.             if (!tflag && QCOND2) {
  729.                 fprintf(stdout, ExtractMsg, "unshrinking", filename,
  730.                   (aflag != 1 /* && pInfo->textfile == pInfo->textmode */ )? ""
  731.                   : (pInfo->textfile? txt : bin), cflag? "\n" : "");
  732.                 fflush(stdout);
  733.             }
  734.             if ((r = unshrink()) != PK_COOL) {
  735.                 if ((tflag && qflag) || (!tflag && !QCOND2))
  736.                     fprintf(stderr,
  737.                       "  error:  not enough memory to unshrink %s\n", filename);
  738.                 else
  739.                     fprintf(stderr,
  740.                       "\n  error:  not enough memory for unshrink operation\n");
  741.                 error = r;
  742.             }
  743.             break;
  744.  
  745.         case REDUCED1:
  746.         case REDUCED2:
  747.         case REDUCED3:
  748.         case REDUCED4:
  749.             if (!tflag && QCOND2) {
  750.                 fprintf(stdout, ExtractMsg, "unreducing", filename,
  751.                   (aflag != 1 /* && pInfo->textfile == pInfo->textmode */ )? ""
  752.                   : (pInfo->textfile? txt : bin), cflag? "\n" : "");
  753.                 fflush(stdout);
  754.             }
  755.             unreduce();
  756.             break;
  757.  
  758.         case IMPLODED:
  759.             if (!tflag && QCOND2) {
  760.                 fprintf(stdout, ExtractMsg, "exploding", filename,
  761.                   (aflag != 1 /* && pInfo->textfile == pInfo->textmode */ )? ""
  762.                   : (pInfo->textfile? txt : bin), cflag? "\n" : "");
  763.                 fflush(stdout);
  764.             }
  765.             if (((r = explode()) != 0) && (r != 5)) {   /* treat 5 specially */
  766.                 if ((tflag && qflag) || (!tflag && !QCOND2))
  767.                     fprintf(stderr, "  error:  %s%s\n", r == 3?
  768.                       "not enough memory to explode " :
  769.                       "invalid compressed (imploded) data for ", filename);
  770.                 else
  771.                     fprintf(stderr, "\n  error:  %s\n", r == 3?
  772.                       "not enough memory for explode operation" :
  773.                       "invalid compressed data for explode format");
  774.                 error = (r == 3)? PK_MEM2 : PK_ERR;
  775.             }
  776.             if (r == 5) {
  777.                 int warning = ((ulg)used_csize <= lrec.csize);
  778.  
  779.                 if ((tflag && qflag) || (!tflag && !QCOND2))
  780.                     fprintf(stderr, LengthMsg, "", warning? "warning":"error",
  781.                       used_csize, lrec.ucsize, warning? "  ":"", lrec.csize,
  782.                       " [", filename, "]");
  783.                 else
  784.                     fprintf(stderr, LengthMsg, "\n", warning? "warning":"error",
  785.                       used_csize, lrec.ucsize, warning? "  ":"", lrec.csize,
  786.                       "", "", ".");
  787.                 error = warning? PK_WARN : PK_ERR;
  788.             }
  789.             break;
  790. #endif /* !SFX */
  791.  
  792.         case DEFLATED:
  793.             if (!tflag && QCOND2) {
  794.                 fprintf(stdout, ExtractMsg, "inflating", filename,
  795.                   (aflag != 1 /* && pInfo->textfile == pInfo->textmode */ )? ""
  796.                   : (pInfo->textfile? txt : bin), cflag? "\n" : "");
  797.                 fflush(stdout);
  798.             }
  799.             if ((r = inflate()) != 0) {
  800.                 if ((tflag && qflag) || (!tflag && !QCOND2))
  801.                     fprintf(stderr, "  error:  %s%s\n", r == 3?
  802.                       "not enough memory to inflate " :
  803.                       "invalid compressed (deflated) data for ", filename);
  804.                 else
  805.                     fprintf(stderr, "\n  error:  %s\n", r == 3?
  806.                       "not enough memory for inflate operation" :
  807.                       "invalid compressed data for inflate format");
  808.                 error = (r == 3)? PK_MEM2 : PK_ERR;
  809.             }
  810.             break;
  811.  
  812.         default:   /* should never get to this point */
  813.             fprintf(stderr, "%s:  unknown compression method\n", filename);
  814.             /* close and delete file before return? */
  815.             return PK_WARN;
  816.  
  817.     } /* end switch (compression method) */
  818.  
  819.     if (disk_full) {            /* set by flush() */
  820.         if (disk_full > 1)
  821.             return PK_DISK;
  822.         error = PK_WARN;
  823.     }
  824.  
  825. /*---------------------------------------------------------------------------
  826.     Close the file and set its date and time (not necessarily in that order),
  827.     and make sure the CRC checked out OK.  Logical-AND the CRC for 64-bit
  828.     machines (redundant on 32-bit machines).
  829.   ---------------------------------------------------------------------------*/
  830.  
  831.     if (!tflag && !cflag)   /* don't close NULL file or stdout */
  832.         close_outfile();
  833.  
  834.     if (error > PK_WARN)  /* don't print redundant CRC error if error already */
  835.         return error;
  836.  
  837.     if ((crc32val = ((~crc32val) & 0xFFFFFFFFL)) != lrec.crc32) {
  838.         /* if quiet enough, we haven't output the filename yet:  do it */
  839.         if ((tflag && qflag) || (!tflag && !QCOND2))
  840.             fprintf(stderr, "%-22s ", filename);
  841.         fprintf(stderr, " bad CRC %08lx  (should be %08lx)\n", crc32val,
  842.                 lrec.crc32);
  843.         FFLUSH(stderr);
  844.         error = PK_ERR;
  845.     } else if (tflag) {
  846.         if (!qflag)
  847.             fprintf(stdout, " OK\n");
  848.     } else {
  849.         if (QCOND2 && !error)
  850.             fprintf(stdout, "\n");
  851.     }
  852.  
  853.     return error;
  854.  
  855. } /* end function extract_or_test_member() */
  856.  
  857.  
  858.  
  859.  
  860.  
  861. /***************************/
  862. /*  Function memextract()  */
  863. /***************************/
  864.  
  865. int memextract(tgt, tgtsize, src, srcsize)   /* extract compressed extra */
  866.     uch *tgt, *src;                          /*  field block; return PK- */
  867.     ulg tgtsize, srcsize;                    /*  type error level */
  868. {
  869.     uch *old_inptr=inptr;
  870.     int  old_incnt=incnt, r, error=PK_OK;
  871.     ush  method;
  872.     ulg  extra_field_crc;
  873.  
  874.  
  875.     method = makeword(src);
  876.     extra_field_crc = makelong(src+2);
  877.  
  878.     /* compressed extra field exists completely in memory at this location: */
  879.     inptr = src + 2 + 4;      /* method and extra_field_crc */
  880.     incnt = (int)(csize = (long)(srcsize - (2 + 4)));
  881.     mem_mode = TRUE;
  882.  
  883.     switch (method) {
  884.         case STORED:
  885.             memcpy((char *)tgt, (char *)inptr, (extent)incnt);
  886.             outcnt = csize;   /* for CRC calculation */
  887.             break;
  888.         case DEFLATED:
  889.             if ((r = inflate()) != 0) {
  890.                 fprintf(stderr, "error:  %s\n", r == 3 ?
  891.                   "not enough memory for inflate operation" :
  892.                   "invalid compressed data for the inflate format");
  893.                 error = (r == 3)? PK_MEM2 : PK_ERR;
  894.             }
  895.             if (outcnt == 0L)   /* inflate's final FLUSH sets outcnt */
  896.                 break;
  897.             if (outcnt <= tgtsize)
  898.                 memcpy((char *)tgt, (char *)slide, (extent)outcnt);
  899.             else
  900.                 error = PK_MEM3;   /* GRR:  should be passed up via SetEAs() */
  901.             break;
  902.         default:
  903.             fprintf(stderr,
  904.               "warning:  unsupported extra field compression type--skipping\n");
  905.             error = PK_WARN;   /* GRR:  should be passed on up via SetEAs() */
  906.             break;
  907.     }
  908.  
  909.     inptr = old_inptr;
  910.     incnt = old_incnt;
  911.     mem_mode = FALSE;
  912.  
  913.     if (!error) {
  914.         register ulg crcval = 0xFFFFFFFFL;
  915.         register ulg n = outcnt;   /* or tgtsize?? */
  916.         register uch *p = tgt;
  917.  
  918.         while (n--)
  919.             crcval = crc_32_tab[((uch)crcval ^ (*p++)) & 0xff] ^ (crcval >> 8);
  920.         crcval = (~crcval) & 0xFFFFFFFFL;
  921.  
  922.         if (crcval != extra_field_crc) {
  923.             fprintf(stderr,
  924.               "error [%s]:  bad extra field CRC %08lx (should be %08lx)\n",
  925.               zipfn, crcval, extra_field_crc);
  926.             error = PK_WARN;
  927.         }
  928.     }
  929.     return error;
  930.  
  931. } /* end function memextract() */
  932.