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