⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 extract.c

📁 WINDOWS下的ZIP解压软件,我是个学生,请让我加入这个网站学习
💻 C
📖 第 1 页 / 共 3 页
字号:
/*---------------------------------------------------------------------------

  extract.c

  This file contains the high-level routines ("driver routines") for extrac-
  ting and testing zipfile members.  It calls the low-level routines in files
  explode.c, inflate.c, unreduce.c and unshrink.c.

  ---------------------------------------------------------------------------*/


#include "unzip.h"
#ifdef  MSWIN
#  include "wizunzip.h"
#  include "replace.h"
#endif /* MSWIN */


/************************************/
/*  Extract Local Prototypes, etc.  */
/************************************/

static int store_info __((void));
static int extract_or_test_member __((void));
#ifdef CRYPT
   static int decrypt_member __((void));
   static int testp __((byte *hdr));
#endif

static byte *mem_i_buffer;
static byte *mem_o_buffer;
static ULONG mem_i_size, mem_i_offset;
static ULONG mem_o_size, mem_o_offset;

static char *VersionMsg =
  " skipping: %-22s  need %s compat. v%u.%u (can do v%u.%u)\n";
static char *ComprMsg =
  " skipping: %-22s  compression method %d\n";
static char *FilNamMsg =
  "%s:  bad filename length (%s)\n";
static char *ExtFieldMsg =
  "%s:  bad extra field length (%s)\n";
static char *OffsetMsg =
  "file #%d:  bad zipfile offset (%s)\n";





/**************************************/
/*  Function extract_or_test_files()  */
/**************************************/

int extract_or_test_files()    /* return PK-type error code */
{
    char **fnamev;
    byte *cd_inptr;
    int cd_incnt, error, error_in_archive=0;
    int renamed, query, len, filnum=(-1), blknum=0;
#ifdef OS2
    extern int longname;  /* from os2unzip.c */
#endif
    UWORD i, j, members_remaining, num_skipped=0, num_bad_pwd=0;
    longint cd_bufstart, bufstart, inbuf_offset, request;
    min_info info[DIR_BLKSIZ];


/*---------------------------------------------------------------------------
    The basic idea of this function is as follows.  Since the central di-
    rectory lies at the end of the zipfile and the member files lie at the
    beginning or middle or wherever, it is not very desirable to simply
    read a central directory entry, jump to the member and extract it, and
    then jump back to the central directory.  In the case of a large zipfile
    this would lead to a whole lot of disk-grinding, especially if each mem-
    ber file is small.  Instead, we read from the central directory the per-
    tinent information for a block of files, then go extract/test the whole
    block.  Thus this routine contains two small(er) loops within a very
    large outer loop:  the first of the small ones reads a block of files
    from the central directory; the second extracts or tests each file; and
    the outer one loops over blocks.  There's some file-pointer positioning
    stuff in between, but that's about it.  Btw, it's because of this jump-
    ing around that we can afford to be lenient if an error occurs in one of
    the member files:  we should still be able to go find the other members,
    since we know the offset of each from the beginning of the zipfile.

    Begin main loop over blocks of member files.  We know the entire central
    directory is on this disk:  we would not have any of this information un-
    less the end-of-central-directory record was on this disk, and we would
    not have gotten to this routine unless this is also the disk on which
    the central directory starts.  In practice, this had better be the ONLY
    disk in the archive, but maybe someday we'll add multi-disk support.
  ---------------------------------------------------------------------------*/

    pInfo = info;
    members_remaining = ecrec.total_entries_central_dir;

    while (members_remaining) {
        j = 0;

        /*
         * Loop through files in central directory, storing offsets, file
         * attributes, and case-conversion flags until block size is reached.
         */

        while (members_remaining && (j < DIR_BLKSIZ)) {
            --members_remaining;
            pInfo = &info[j];

            if (readbuf(sig, 4) <= 0) {
                error_in_archive = 51;  /* 51:  unexpected EOF */
                members_remaining = 0;  /* ...so no more left to do */
                break;
            }
            if (strncmp(sig, central_hdr_sig, 4)) {  /* just to make sure */
                fprintf(stderr, CentSigMsg, j);  /* sig not found */
                fprintf(stderr, ReportMsg);   /* check binary transfers */
                error_in_archive = 3;   /* 3:  error in zipfile */
                members_remaining = 0;  /* ...so no more left to do */
                break;
            }
            /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
            if ((error = process_cdir_file_hdr()) != 0) {
                error_in_archive = error;   /* only 51 (EOF) defined */
                members_remaining = 0;  /* ...so no more left to do */
                break;
            }
            if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
                if (error > error_in_archive)
                    error_in_archive = error;
                if (error > 1) {  /* fatal:  no more left to do */
                    fprintf(stderr, FilNamMsg, filename, "central");
                    members_remaining = 0;
                    break;
                }
            }
            if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0)
            {
                if (error > error_in_archive)
                    error_in_archive = error;
                if (error > 1) {  /* fatal */
                    fprintf(stderr, ExtFieldMsg, filename, "central");
                    members_remaining = 0;
                    break;
                }
            }
            if ((error = do_string(crec.file_comment_length, SKIP)) != 0) {
                if (error > error_in_archive)
                    error_in_archive = error;
                if (error > 1) {  /* fatal */
                    fprintf(stderr, "\n%s:  bad file comment length\n",
                            filename);
                    members_remaining = 0;
                    break;
                }
            }
            if (process_all_files) {
                if (store_info())
                    ++num_skipped;
                else
                    ++j;  /* file is OK: save info[] and continue with next */
            } else {
                fnamev = fnv;   /* don't destroy permanent filename pointer */
                for (--fnamev; *++fnamev;)
                    if (match(filename, *fnamev)) {
                        if (store_info())
                            ++num_skipped;
                        else
                            ++j;   /* file is OK */
                        break;  /* found match for filename, so stop looping */
                    } /* end if (match), for-loop (fnamev) */
            } /* end if (process_all_files) */

        } /* end while-loop (adding files to current block) */

        /* save position in central directory so can come back later */
        cd_bufstart = cur_zipfile_bufstart;
        cd_inptr = inptr;
        cd_incnt = incnt;

    /*-----------------------------------------------------------------------
        Second loop:  process files in current block, extracting or testing
        each one.
      -----------------------------------------------------------------------*/

        for (i = 0; i < j; ++i) {
            filnum = i + blknum*DIR_BLKSIZ;
            pInfo = &info[i];
            /*
             * if the target position is not within the current input buffer
             * (either haven't yet read far enough, or (maybe) skipping back-
             * ward) skip to the target position and reset readbuf().
             */
            /* LSEEK(pInfo->offset):  */
            request = pInfo->offset + extra_bytes;
            inbuf_offset = request % INBUFSIZ;
            bufstart = request - inbuf_offset;

            if (request < 0) {
                fprintf(stderr, SeekMsg, ReportMsg);
                error_in_archive = 3;       /* 3:  severe error in zipfile, */
                continue;                   /*  but can still go on */
            } else if (bufstart != cur_zipfile_bufstart) {
                cur_zipfile_bufstart = lseek(zipfd, bufstart, SEEK_SET);
                if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0) {
                    fprintf(stderr, OffsetMsg, filnum, "lseek");
                    error_in_archive = 3;   /* 3:  error in zipfile, but */
                    continue;               /*  can still do next file   */
                }
                inptr = inbuf + (int)inbuf_offset;
                incnt -= (int)inbuf_offset;
            } else {
                incnt += (inptr-inbuf) - (int)inbuf_offset;
                inptr = inbuf + (int)inbuf_offset;
            }

            /* should be in proper position now, so check for sig */
            if (readbuf(sig, 4) <= 0) {  /* bad offset */
                fprintf(stderr, OffsetMsg, filnum, "EOF");
                error_in_archive = 3;    /* 3:  error in zipfile */
                continue;       /* but can still try next one */
            }
            if (strncmp(sig, local_hdr_sig, 4)) {
                fprintf(stderr, OffsetMsg, filnum,
                        "can't find local header sig");   /* bad offset */
                error_in_archive = 3;
                continue;
            }
            if ((error = process_local_file_hdr()) != 0) {
                fprintf(stderr, "\nfile #%d:  bad local header\n", filnum);
                error_in_archive = error;       /* only 51 (EOF) defined */
                continue;       /* can still try next one */
            }
            if ((error = do_string(lrec.filename_length, FILENAME)) != 0) {
                if (error > error_in_archive)
                    error_in_archive = error;
                if (error > 1) {
                    fprintf(stderr, FilNamMsg, filename, "local");
                    continue;   /* go on to next one */
                }
            }
            if (extra_field != (byte *)NULL)
                free(extra_field);
            extra_field = (byte *)NULL;
            if ((error = do_string(lrec.extra_field_length, EXTRA_FIELD)) != 0)
            {
                if (error > error_in_archive)
                    error_in_archive = error;
                if (error > 1) {
                    fprintf(stderr, ExtFieldMsg, filename, "local");
                    continue;   /* go on */
                }
            }

            /*
             * just about to extract file:  if extracting to disk, check if
             * already exists, and if so, take appropriate action according to
             * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
             * loop because we don't store the possibly renamed filename[] in
             * info[])
             */
            if (!tflag && !cflag) {
                renamed = FALSE;   /* user hasn't renamed output file yet */
#ifdef OS2
                longname = FALSE;  /* no long name has yet been stored */
#endif

startover:
                query = FALSE;
#ifdef MACOS
                macflag = (pInfo->hostnum == MAC_);
#endif
                /* mapname can create dirs if not freshening or if renamed */
                if ((error = mapname(!fflag || renamed)) > 1) {    /* skip */
                    if ((error > 2) && (error_in_archive < 2))
                        error_in_archive = 2;   /* (weak) error in zipfile */
                    continue;   /* go on to next file */
                }

                switch (check_for_newer(filename)) {
                    case DOES_NOT_EXIST:
                        if (fflag && !renamed)  /* don't skip if just renamed */
                            continue;   /* freshen (no new files):  skip */
                        break;
                    case EXISTS_AND_OLDER:
                        if (overwrite_none)
                            continue;   /* never overwrite:  skip file */
                        if (!overwrite_all && !force_flag)
                            query = TRUE;
                        break;
                    case EXISTS_AND_NEWER:             /* (or equal) */
                        if (overwrite_none || (uflag && !renamed))
                            continue;  /* skip if update/freshen & orig name */
                        if (!overwrite_all && !force_flag)
                            query = TRUE;
                        break;
                }
/*#ifndef VMS*/ /* VMS creates higher version number instead of overwriting
                 * (will have to modify for VMS-style names with specific
                 *  version numbers:  just check V_flag?  don't use stat?) */
                if (query) {
#ifdef MSWIN
                    FARPROC lpfnprocReplace;
                    int ReplaceDlgRetVal;   /* replace dialog return value */

                    ShowCursor(FALSE);      /* turn off cursor */
                    SetCursor(hSaveCursor); /* restore the cursor */
                    lpfnprocReplace = MakeProcInstance(ReplaceProc, hInst);
                    ReplaceDlgRetVal = DialogBoxParam(hInst, "Replace",
                      hWndMain, lpfnprocReplace, (DWORD)(LPSTR)filename);
                    FreeProcInstance(lpfnprocReplace);
                    hSaveCursor = SetCursor(hHourGlass);
                    ShowCursor(TRUE);
                    switch (ReplaceDlgRetVal) {
                        case IDM_REPLACE_RENAME:
                            renamed = TRUE;
                            goto startover;   /* sorry for a goto */
                        case IDM_REPLACE_YES:
                            break;
                        case IDM_REPLACE_ALL:
                            overwrite_all = TRUE;
                            overwrite_none = FALSE;  /* just to make sure */
                            break;
                        case IDM_REPLACE_NONE:
                            overwrite_none = TRUE;
                            overwrite_all = FALSE;  /* make sure */
                            force_flag = FALSE;     /* ditto */
                            /* FALL THROUGH, skip */
                        case IDM_REPLACE_NO:
                            continue;
                    }
#else /* !MSWIN */
reprompt:
                    fprintf(stderr,
                      "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
                      filename);
                    FFLUSH   /* for Amiga and Mac MPW */
                    fgets(answerbuf, 9, stdin);
                    switch (*answerbuf) {
                        case 'A':   /* dangerous option:  force caps */
                            overwrite_all = TRUE;
                            overwrite_none = FALSE;  /* just to make sure */
                            break;
                        case 'r':
                        case 'R':
                            do {
                                fprintf(stderr, "new name: ");
                                FFLUSH   /* for AMIGA and Mac MPW */
                                fgets(filename, FILNAMSIZ, stdin);
                                /* usually get \n here:  better check for it */
                                len = strlen(filename);
                                if (filename[len-1] == '\n')
                                    filename[--len] = 0;
                            } while (len == 0);
                            renamed = TRUE;
                            goto startover;   /* sorry for a goto */
                        case 'y':
                        case 'Y':
                            break;
                        case 'N':

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -