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

📄 zipfile.c

📁 给出了 zip 压缩算法的完整实现过程。
💻 C
📖 第 1 页 / 共 4 页
字号:
  PUTLG(z->tim, f);  PUTLG(z->crc, f);  PUTLG(z->siz, f);  PUTLG(z->len, f);  PUTSH(z->nam, f);  PUTSH(z->cext, f);  PUTSH(z->com, f);  PUTSH(z->dsk, f);  PUTSH(z->att, f);  PUTLG(z->atx, f);  PUTLG(z->off, f);#ifdef EBCDIC  if (z->com)    memtoasc(z->comment, z->comment, z->com);#endif /* EBCDIC */  if (fwrite(z->iname, 1, z->nam, f) != z->nam ||      (z->cext && fwrite(z->cextra, 1, z->cext, f) != z->cext) ||      (z->com && fwrite(z->comment, 1, z->com, f) != z->com))    return ZE_TEMP;  return ZE_OK;}int putend(n, s, c, m, z, f)unsigned n;             /* number of entries in central directory */ulg s;                  /* size of central directory */ulg c;                  /* offset of central directory */extent m;               /* length of zip file comment (0 if none) */char *z;                /* zip file comment if m != 0 */FILE *f;                /* file to write to *//* Write the end of central directory data to file *f.  Return an error code   in the ZE_ class. */{  PUTLG(ENDSIG, f);  PUTSH(0, f);  PUTSH(0, f);  PUTSH(n, f);  PUTSH(n, f);  PUTLG(s, f);  PUTLG(c, f);  PUTSH(m, f);/* Write the comment, if any */#ifdef EBCDIC  memtoasc(z, z, m);#endif  if (m && fwrite(z, 1, m, f) != m)    return ZE_TEMP;#ifdef HANDLE_AMIGA_SFX  if (amiga_sfx_offset && zipbeg /* -J zeroes this */) {    s = ftell(f);    while (s & 3) s++, putc(0, f);   /* final marker must be longword aligned */    PUTLG(0xF2030000 /* 1010 in Motorola byte order */, f);    c = (s - amiga_sfx_offset - 4) / 4;  /* size of archive part in longwords */    if (fseek(f, amiga_sfx_offset, SEEK_SET) != 0)      return ZE_TEMP;    c = ((c >> 24) & 0xFF) | ((c >> 8) & 0xFF00)         | ((c & 0xFF00) << 8) | ((c & 0xFF) << 24);     /* invert byte order */    PUTLG(c, f);    fseek(f, 0, SEEK_END);                                    /* just in case */  }#endif  return ZE_OK;}/* Note: a zip "entry" includes a local header (which includes the file   name), an encryption header if encrypting, the compressed data   and possibly an extended local header. */int zipcopy(z, x, y)struct zlist far *z;    /* zip entry to copy */FILE *x, *y;            /* source and destination files *//* Copy the zip entry described by *z from file *x to file *y.  Return an   error code in the ZE_ class.  Also update tempzn by the number of bytes   copied. */{  ulg n;                /* holds local header offset */  Trace((stderr, "zipcopy %s\n", z->zname));  n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext;  if (fix > 1) {    if (fseek(x, z->off + n, SEEK_SET)) /* seek to compressed data */      return ferror(x) ? ZE_READ : ZE_EOF;    if (fix > 2) {      /* Update length of entry's name, it may have been changed.  This is         needed to support the ZipNote ability to rename archive entries. */      z->nam = strlen(z->iname);      n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext;    }    /* do not trust the old compressed size */    if (putlocal(z, y) != ZE_OK)      return ZE_TEMP;    z->off = tempzn;    tempzn += n;    n = z->siz;  } else {    if (fseek(x, z->off, SEEK_SET))     /* seek to local header */      return ferror(x) ? ZE_READ : ZE_EOF;    z->off = tempzn;    n += z->siz;  }  /* copy the compressed data and the extended local header if there is one */  if (z->lflg & 8) n += 16;  tempzn += n;  return fcopy(x, y, n);}#ifndef UTIL#ifdef USE_EF_UT_TIMElocal int ef_scan_ut_time(ef_buf, ef_len, ef_is_cent, z_utim)char *ef_buf;                   /* buffer containing extra field */extent ef_len;                  /* total length of extra field */int ef_is_cent;                 /* flag indicating "is central extra field" */iztimes *z_utim;                /* return storage: atime, mtime, ctime *//* This function scans the extra field for EF_TIME or EF_IZUNIX blocks * containing Unix style time_t (GMT) values for the entry's access, creation * and modification time. * If a valid block is found, all time stamps are copied to the iztimes * structure. * The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring * all data from probably present obsolete EF_IZUNIX blocks. * If multiple blocks of the same type are found, only the information from * the last block is used. * The return value is the EF_TIME Flags field (simulated in case of an * EF_IZUNIX block) or 0 in case of failure. */{  int flags = 0;  unsigned eb_id;  extent eb_len;  int have_new_type_eb = FALSE;  if (ef_len == 0 || ef_buf == NULL)    return 0;  Trace((stderr,"\nef_scan_ut_time: scanning extra field of length %u\n",         ef_len));  while (ef_len >= EB_HEADSIZE) {    eb_id = SH(EB_ID + ef_buf);    eb_len = SH(EB_LEN + ef_buf);    if (eb_len > (ef_len - EB_HEADSIZE)) {      /* Discovered some extra field inconsistency! */      Trace((stderr,"ef_scan_ut_time: block length %u > rest ef_size %u\n",             eb_len, ef_len - EB_HEADSIZE));      break;    }    switch (eb_id) {      case EF_TIME:        flags &= ~0x00ff;       /* ignore previous IZUNIX or EF_TIME fields */        have_new_type_eb = TRUE;        if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) {           unsigned eb_idx = EB_UT_TIME1;           Trace((stderr,"ef_scan_ut_time: Found TIME extra field\n"));           flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x00ff);           if ((flags & EB_UT_FL_MTIME)) {              if ((eb_idx+4) <= eb_len) {                 z_utim->mtime = LG((EB_HEADSIZE+eb_idx) + ef_buf);                 eb_idx += 4;                 Trace((stderr,"  Unix EF modtime = %ld\n", z_utim->mtime));              } else {                 flags &= ~EB_UT_FL_MTIME;                 Trace((stderr,"  Unix EF truncated, no modtime\n"));              }           }           if (ef_is_cent) {              break;            /* central version of TIME field ends here */           }           if (flags & EB_UT_FL_ATIME) {              if ((eb_idx+4) <= eb_len) {                 z_utim->atime = LG((EB_HEADSIZE+eb_idx) + ef_buf);                 eb_idx += 4;                 Trace((stderr,"  Unix EF acctime = %ld\n", z_utim->atime));              } else {                 flags &= ~EB_UT_FL_ATIME;              }           }           if (flags & EB_UT_FL_CTIME) {              if ((eb_idx+4) <= eb_len) {                 z_utim->ctime = LG((EB_HEADSIZE+eb_idx) + ef_buf);                 /* eb_idx += 4; */  /* superfluous for now ... */                 Trace((stderr,"  Unix EF cretime = %ld\n", z_utim->ctime));              } else {                 flags &= ~EB_UT_FL_CTIME;              }           }        }        break;      case EF_IZUNIX2:        if (!have_new_type_eb) {           flags &= ~0x00ff;    /* ignore any previous IZUNIX field */           have_new_type_eb = TRUE;        }        break;      case EF_IZUNIX:        if (eb_len >= EB_UX_MINLEN) {           Trace((stderr,"ef_scan_ut_time: Found IZUNIX extra field\n"));           if (have_new_type_eb) {              break;            /* Ignore IZUNIX extra field block ! */           }           z_utim->atime = LG((EB_HEADSIZE+EB_UX_ATIME) + ef_buf);           z_utim->mtime = LG((EB_HEADSIZE+EB_UX_MTIME) + ef_buf);           Trace((stderr,"  Unix EF access time = %ld\n",z_utim->atime));           Trace((stderr,"  Unix EF modif. time = %ld\n",z_utim->mtime));           flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME);  /* signal success */        }        break;      case EF_THEOS:/*      printf("Not implemented yet\n"); */        break;      default:        break;    }    /* Skip this extra field block */    ef_buf += (eb_len + EB_HEADSIZE);    ef_len -= (eb_len + EB_HEADSIZE);  }  return flags;}int get_ef_ut_ztime(z, z_utim)struct zlist far *z;iztimes *z_utim;{  int r;#ifdef IZ_CHECK_TZ  if (!zp_tz_is_valid) return 0;#endif  /* First, scan local extra field. */  r = ef_scan_ut_time(z->extra, z->ext, FALSE, z_utim);  /* If this was not successful, try central extra field, but only if     it is really different. */  if (!r && z->cext > 0 && z->cextra != z->extra)    r = ef_scan_ut_time(z->cextra, z->cext, TRUE, z_utim);  return r;}#endif /* USE_EF_UT_TIME */local void cutpath(p, delim)char *p;                /* path string */int delim;              /* path component separator char *//* Cut the last path component off the name *p in place. * This should work on both internal and external names. */{  char *r;              /* pointer to last path delimiter */#ifdef VMS                      /* change [w.x.y]z to [w.x]y.DIR */  if ((r = MBSRCHR(p, ']')) != NULL)  {    *r = 0;    if ((r = MBSRCHR(p, '.')) != NULL)    {      *r = ']';      strcat(r, ".DIR;1");     /* this assumes a little padding--see PAD */    } else {      *p = 0;    }  } else {    if ((r = MBSRCHR(p, delim)) != NULL)      *r = 0;    else      *p = 0;  }#else /* !VMS */  if ((r = MBSRCHR(p, delim)) != NULL)    *r = 0;  else    *p = 0;#endif /* ?VMS */}int trash()/* Delete the compressed files and the directories that contained the deleted   files, if empty.  Return an error code in the ZE_ class.  Failure of   destroy() or deletedir() is ignored. */{  extent i;             /* counter on deleted names */  extent n;             /* number of directories to delete */  struct zlist far **s; /* table of zip entries to handle, sorted */  struct zlist far *z;  /* current zip entry */  /* Delete marked names and count directories */  n = 0;  for (z = zfiles; z != NULL; z = z->nxt)    if (z->mark == 1 || z->trash)    {      z->mark = 1;      if (z->iname[z->nam - 1] != (char)0x2f) { /* don't unlink directory */        if (verbose)          fprintf(mesg, "zip diagnostic: deleting file %s\n", z->name);        if (destroy(z->name)) {          zipwarn("error deleting ", z->name);        }        /* Try to delete all paths that lead up to marked names. This is         * necessary only with the -D option.         */        if (!dirnames) {          cutpath(z->name, '/');  /* XXX wrong ??? */          cutpath(z->iname, 0x2f); /* 0x2f = ascii['/'] */          z->nam = strlen(z->iname);          if (z->nam > 0) {            z->iname[z->nam - 1] = (char)0x2f;            z->iname[z->nam++] = '\0';          }          if (z->nam > 0) n++;        }      } else {        n++;      }    }  /* Construct the list of all marked directories. Some may be duplicated   * if -D was used.   */  if (n)  {    if ((s = (struct zlist far **)malloc(n*sizeof(struct zlist far *))) ==        NULL)      return ZE_MEM;    n = 0;    for (z = zfiles; z != NULL; z = z->nxt) {      if (z->mark && z->nam > 0 && z->iname[z->nam - 1] == (char)0x2f /* '/' */          && (n == 0 || strcmp(z->name, s[n-1]->name) != 0)) {        s[n++] = z;      }    }    /* Sort the files in reverse order to get subdirectories first.     * To avoid problems with strange naming conventions as in VMS,     * we sort on the internal names, so x/y/z will always be removed     * before x/y. On VMS, x/y/z > x/y but [x.y.z] < [x.y]     */    qsort((char *)s, n, sizeof(struct zlist far *), rqcmp);    for (i = 0; i < n; i++) {      char *p = s[i]->name;      if (*p == '\0') continue;      if (p[strlen(p) - 1] == '/') { /* keep VMS [x.y]z.dir;1 intact */        p[strlen(p) - 1] = '\0';      }      if (i == 0 || strcmp(s[i]->name, s[i-1]->name) != 0) {        if (verbose) {          fprintf(mesg, "deleting directory %s (if empty)                \n",                  s[i]->name);        }        deletedir(s[i]->name);      }    }    free((zvoid *)s);  }  return ZE_OK;}#endif /* !UTIL */

⌨️ 快捷键说明

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