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

📄 zipfile.c

📁 给出了 zip 压缩算法的完整实现过程。
💻 C
📖 第 1 页 / 共 4 页
字号:
      {        sprintf(errbuf, "%lu", (ulg)zcount + 1);        zipwarn("zero-length name for entry #", errbuf);#ifndef DEBUG        farfree((zvoid far *)z);        return ZE_FORM;#endif      }      if ((z->iname = malloc(z->nam+1)) ==  NULL ||          (z->cext && (z->cextra = malloc(z->cext)) == NULL) ||          (z->com && (z->comment = malloc(z->com)) == NULL))        return ZE_MEM;      if (fread(z->iname, z->nam, 1, f) != 1 ||          (z->cext && fread(z->cextra, z->cext, 1, f) != 1) ||          (z->com && fread(z->comment, z->com, 1, f) != 1))        return ferror(f) ? ZE_READ : ZE_EOF;      z->iname[z->nam] = '\0';                  /* terminate name */#ifdef EBCDIC      if (z->com)         memtoebc(z->comment, z->comment, z->com);#endif /* EBCDIC */      /* Update zipbeg offset, prepare for next header */      if (z->off < zipbeg)         zipbeg = z->off;      zcount++;      /* Read next signature */      if (fread(b, 4, 1, f) != 1)          return ferror(f) ? ZE_READ : ZE_EOF;    }    /* Point to start of header list and read local headers */    z = zfiles;    while (z != NULL) {      /* Read next signature */      if (fseek(f, z->off, SEEK_SET) != 0 || fread(b, 4, 1, f) != 1)        return ferror(f) ? ZE_READ : ZE_EOF;      if (LG(b) == LOCSIG) {        if (fread(b, LOCHEAD, 1, f) != 1)            return ferror(f) ? ZE_READ : ZE_EOF;        z->lflg = SH(LOCFLG + b);        n = SH(LOCNAM + b);        z->ext = SH(LOCEXT + b);        /* Compare name and extra fields */        if (n != z->nam)        {#ifdef EBCDIC          strtoebc(z->iname, z->iname);#endif          zipwarn("name lengths in local and central differ for ", z->iname);          return ZE_FORM;        }        if ((t = malloc(z->nam)) == NULL)          return ZE_MEM;        if (fread(t, z->nam, 1, f) != 1)        {          free((zvoid *)t);          return ferror(f) ? ZE_READ : ZE_EOF;        }        if (memcmp(t, z->iname, z->nam))        {          free((zvoid *)t);#ifdef EBCDIC          strtoebc(z->iname, z->iname);#endif          zipwarn("names in local and central differ for ", z->iname);          return ZE_FORM;        }        free((zvoid *)t);        if (z->ext)        {          if ((z->extra = malloc(z->ext)) == NULL)            return ZE_MEM;          if (fread(z->extra, z->ext, 1, f) != 1)          {            free((zvoid *)(z->extra));            return ferror(f) ? ZE_READ : ZE_EOF;          }          if (z->ext == z->cext && memcmp(z->extra, z->cextra, z->ext) == 0)          {            free((zvoid *)(z->extra));            z->extra = z->cextra;          }        }        /* Check extended local header if there is one */        if ((z->lflg & 8) != 0)        {          char buf2[16];          ulg s;                        /* size of compressed data */          s = LG(LOCSIZ + b);          if (s == 0)            s = LG((CENSIZ-CENVER) + (char far *)(&(z->ver)));          if (fseek(f, (z->off + (4+LOCHEAD) + z->nam + z->ext + s), SEEK_SET)              || (fread(buf2, 16, 1, f) != 1))            return ferror(f) ? ZE_READ : ZE_EOF;          if (LG(buf2) != EXTLOCSIG)          {#ifdef EBCDIC            strtoebc(z->iname, z->iname);#endif            zipwarn("extended local header not found for ", z->iname);            return ZE_FORM;          }          /* overwrite the unknown values of the local header: */          for (n = 0; n < 12; n++)            b[LOCCRC+n] = buf2[4+n];        }        /* Compare local header with that part of central header (except           for the reserved bits in the general purpose flags and except           for the already checked entry name length */        u = (char far *)(&(z->ver));        flg = SH((CENFLG-CENVER) + u);          /* Save central flags word */        u[CENFLG-CENVER+1] &= 0x1f;             /* Mask reserved flag bits */        b[LOCFLG+1] &= 0x1f;        for (m = 0, n = 0; n < LOCNAM; n++)          if (b[n] != u[n])          {            if (!m)            {              zipwarn("local and central headers differ for ", z->zname);              m = 1;            }            if (noisy)            {              sprintf(errbuf, " offset %u--local = %02x, central = %02x",                      (unsigned)n, (uch)b[n], (uch)u[n]);              zipwarn(errbuf, "");            }          }        if (m && !adjust)          return ZE_FORM;        /* Complete the setup of the zlist entry by translating the remaining         * central header fields in memory, starting with the fields with         * highest offset. This order of the conversion commands takes into         * account potential buffer overlaps caused by structure padding.         */        z->len = LG((CENLEN-CENVER) + u);        z->siz = LG((CENSIZ-CENVER) + u);        z->crc = LG((CENCRC-CENVER) + u);        z->tim = LG((CENTIM-CENVER) + u);   /* time and date into one long */        z->how = SH((CENHOW-CENVER) + u);        z->flg = flg;                       /* may be different from z->lflg */        z->ver = SH((CENVER-CENVER) + u);        /* Clear actions */        z->mark = 0;        z->trash = 0;#ifdef UTIL/* We only need z->iname in the utils */        z->name = z->iname;#ifdef EBCDIC/* z->zname is used for printing and must be coded in native charset */        if ((z->zname = malloc(z->nam+1)) ==  NULL)          return ZE_MEM;        strtoebc(z->zname, z->iname);#else        z->zname = z->iname;#endif#else /* !UTIL */        z->zname = in2ex(z->iname);       /* convert to external name */        if (z->zname == NULL)          return ZE_MEM;        z->name = z->zname;#endif /* ?UTIL */      }      else {#ifdef EBCDIC        strtoebc(z->iname, z->iname);#endif        zipwarn("local header not found for ", z->iname);        return ZE_FORM;      }#ifndef UTIL      if (verbose)        zipoddities(z);#endif      z = z->nxt;    }    if (zipbeg && noisy)      fprintf(mesg, "%s: %s a preamble of %lu bytes\n",              zipfile, adjust ? "adjusting offsets for" : "found", zipbeg);#ifdef HANDLE_AMIGA_SFX    if (zipbeg < 12 || (zipbeg & 3) != 0 /* must be longword aligned */)      amiga_sfx_offset = 0;    else if (amiga_sfx_offset) {      char buf2[16];      if (!fseek(f, zipbeg - 12, SEEK_SET) && fread(buf2, 12, 1, f) == 1) {        if (LG(buf2 + 4) == 0xF1030000 /* 1009 in Motorola byte order */)          /* could also check if LG(buf2) == 0xF2030000... no for now */          amiga_sfx_offset = zipbeg - 4;        else          amiga_sfx_offset = 0L;      }    }#endif /* HANDLE_AMIGA_SFX */    return ZE_OK;}/* * readzipfile initializes the global variables that hold the zipfile * directory info and opens the zipfile. For the actual zipfile scan, * the subroutine scanzipf_reg() or scanzipf_fix() is called, * depending on the mode of operation (regular processing, or zipfix mode). */int readzipfile()/*   The name of the zip file is pointed to by the global "zipfile".   The globals zipbeg, zfiles, zcount, and zcomlen are initialized.   Return an error code in the ZE_ class.*/{  FILE *f;              /* zip file */  int retval;           /* return code */  int readable;         /* 1 if zipfile exists and is readable */  /* Initialize zip file info */  zipbeg = 0;  zfiles = NULL;                        /* Points to first header */  zcount = 0;                           /* number of files */  zcomlen = 0;                          /* zip file comment length */  retval = ZE_OK;  f = NULL;                             /* shut up some compilers */  /* If zip file exists, read headers and check structure */#ifdef VMS  if (zipfile == NULL || !(*zipfile) || !strcmp(zipfile, "-"))    return ZE_OK;  {    int rtype;    if ((VMSmunch(zipfile, GET_RTYPE, (char *)&rtype) == RMS$_NORMAL) &&        (rtype == FAT$C_VARIABLE)) {      fprintf(stderr,     "\n     Error:  zipfile is in variable-length record format.  Please\n\     run \"bilf b %s\" to convert the zipfile to fixed-length\n\     record format.\n\n", zipfile);      return ZE_FORM;    }  }  readable = ((f = fopen(zipfile, FOPR)) != NULL);#else /* !VMS */  readable = (zipfile != NULL && *zipfile && strcmp(zipfile, "-") &&              (f = fopen(zipfile, FOPR)) != NULL);#endif /* ?VMS */#ifdef MVS  /* Very nasty special case for MVS.  Just because the zipfile has been   * opened for reading does not mean that we can actually read the data.   * Typical JCL to create a zipfile is   *   * //ZIPFILE  DD  DISP=(NEW,CATLG),DSN=prefix.ZIP,   * //             SPACE=(CYL,(10,10))   *   * That creates a VTOC entry with an end of file marker (DS1LSTAR) of zero.   * Alas the VTOC end of file marker is only used when the file is opened in   * append mode.  When a file is opened in read mode, the "other" end of file   * marker is used, a zero length data block signals end of file when reading.   * With a brand new file which has not been written to yet, it is undefined   * what you read off the disk.  In fact you read whatever data was in the same   * disk tracks before the zipfile was allocated.  You would be amazed at the   * number of application programmers who still do not understand this.  Makes   * for interesting and semi-random errors, GIGO.   *   * Newer versions of SMS will automatically write a zero length block when a   * file is allocated.  However not all sites run SMS or they run older levels   * so we cannot rely on that.  The only safe thing to do is close the file,   * open in append mode (we already know that the file exists), close it again,   * reopen in read mode and try to read a data block.  Opening and closing in   * append mode will write a zero length block where DS1LSTAR points, making   * sure that the VTOC and internal end of file markers are in sync.  Then it   * is safe to read data.  If we cannot read one byte of data after all that,   * it is a brand new zipfile and must not be read.   */  if (readable)  {    char c;    fclose(f);    /* append mode */    if ((f = fopen(zipfile, "ab")) == NULL) {      ZIPERR(ZE_OPEN, zipfile);    }    fclose(f);    /* read mode again */    if ((f = fopen(zipfile, FOPR)) == NULL) {      ZIPERR(ZE_OPEN, zipfile);    }    if (fread(&c, 1, 1, f) != 1) {      /* no actual data */      readable = 0;      fclose(f);    }    else{      fseek(f, 0, SEEK_SET);  /* at least one byte in zipfile, back to the start */    }  }#endif /* MVS */  if (readable)  {#ifndef UTIL    retval = (fix && !adjust) ? scanzipf_fix(f) : scanzipf_reg(f);#else    retval = scanzipf_reg(f);#endif    /* Done with zip file for now */    fclose(f);    /* If one or more files, sort by name */    if (zcount)    {      struct zlist far * far *x;    /* pointer into zsort array */      struct zlist far *z;          /* pointer into zfiles linked list */      extent zl_size = zcount * sizeof(struct zlist far *);      if (zl_size / sizeof(struct zlist far *) != zcount ||          (x = zsort = (struct zlist far **)malloc(zl_size)) == NULL)        return ZE_MEM;      for (z = zfiles; z != NULL; z = z->nxt)        *x++ = z;      qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp);    }  }  return retval;}int putlocal(z, f)struct zlist far *z;    /* zip entry to write local header for */FILE *f;                /* file to write to *//* Write a local header described by *z to file *f.  Return an error code   in the ZE_ class. */{  PUTLG(LOCSIG, f);  PUTSH(z->ver, f);  PUTSH(z->lflg, f);  PUTSH(z->how, f);  PUTLG(z->tim, f);  PUTLG(z->crc, f);  PUTLG(z->siz, f);  PUTLG(z->len, f);  PUTSH(z->nam, f);  PUTSH(z->ext, f);  if (fwrite(z->iname, 1, z->nam, f) != z->nam ||      (z->ext && fwrite(z->extra, 1, z->ext, f) != z->ext))    return ZE_TEMP;  return ZE_OK;}int putextended(z, f)struct zlist far *z;    /* zip entry to write local header for */FILE *f;                /* file to write to *//* Write an extended local header described by *z to file *f. * Return an error code in the ZE_ class. */{  PUTLG(EXTLOCSIG, f);  PUTLG(z->crc, f);  PUTLG(z->siz, f);  PUTLG(z->len, f);  return ZE_OK;}int putcentral(z, f)struct zlist far *z;    /* zip entry to write central header for */FILE *f;                /* file to write to *//* Write a central header described by *z to file *f.  Return an error code   in the ZE_ class. */{  PUTLG(CENSIG, f);  PUTSH(z->vem, f);  PUTSH(z->ver, f);  PUTSH(z->flg, f);  PUTSH(z->how, f);

⌨️ 快捷键说明

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