zipfile.c
来自「infozip2.2源码」· C语言 代码 · 共 1,465 行 · 第 1/3 页
C
1,465 行
sprintf(errbuf, "%ld", (ulg)zcount + 1); zipwarn("zero-length name for entry #", errbuf);#ifndef DEBUG return ZE_FORM;#endif } if ((z->iname = malloc(n+1)) == NULL || (z->ext && (z->extra = malloc(z->ext)) == NULL)) return ZE_MEM; if (fread(z->iname, n, 1, f) != 1 || (z->ext && fread(z->extra, z->ext, 1, f) != 1) || (s && fseek(f, (long)s, SEEK_CUR))) return ferror(f) ? ZE_READ : ZE_EOF; /* If there is an extended local header, s is either 0 or * the correct compressed size. */ z->iname[n] = 0; /* terminate name */ z->zname = in2ex(z->iname); /* convert to external name */ if (z->zname == NULL) return ZE_MEM; z->name = z->zname; z->cextra = z->extra; if (noisy) fprintf(mesg, "zip: reading %s\n", z->zname); /* Save offset, update for next header */ z->off = p; p += 4 + LOCHEAD + n + z->ext + s; zcount++; /* Skip extended local header if there is one */ if ((flg & 8) != 0) { /* Skip the compressed data if compressed size is unknown. * For safety, we should use the central directory. */ if (s == 0) { for (;;) { while ((m = getc(f)) != EOF && m != 0x50) ; /* 0x50 == 'P' */ b[0] = (char) m; if (fread(b+1, 15, 1, f) != 1 || LG(b) == EXTLOCSIG) break; if (fseek(f, -15L, SEEK_CUR)) return ferror(f) ? ZE_READ : ZE_EOF; } s = LG(4 + EXTSIZ + b); p += s; if ((ulg) ftell(f) != p+16L) { zipwarn("bad extended local header for ", z->zname); return ZE_FORM; } } else { /* compressed size non-zero, assume that it is valid: */ Assert(p == ftell(f), "bad compressed size with extended header"); if (fseek(f, p, SEEK_SET) || fread(b, 16, 1, f) != 1) return ferror(f) ? ZE_READ : ZE_EOF; if (LG(b) != EXTLOCSIG) { zipwarn("extended local header not found for ", z->zname); return ZE_FORM; } } /* overwrite the unknown values of the local header: */ /* already in host format */ z->crc = LG(4 + EXTCRC + b); z->siz = s; z->len = LG(4 + EXTLEN + b); p += 16L; } else if (fix > 1) { /* Don't trust the compressed size */ for (;;) { while ((m = getc(f)) != EOF && m != 0x50) p++; /* 0x50 == 'P' */ b[0] = (char) m; if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == CENSIG) break; if (fseek(f, -3L, SEEK_CUR)) return ferror(f) ? ZE_READ : ZE_EOF; p++; } s = p - (z->off + 4 + LOCHEAD + n + z->ext); if (s != z->siz) { fprintf(mesg, " compressed size %ld, actual size %ld for %s\n", z->siz, s, z->zname); z->siz = s; } /* next LOCSIG already read at this point, don't read it again: */ continue; } /* Read next signature */ if (fread(b, 4, 1, f) != 1) break; } s = p; /* save start of central */ if (LG(b) != CENSIG && noisy) { fprintf(mesg, "zip warning: %s %s truncated.\n", zipfile, fix > 1 ? "has been" : "would be"); if (fix == 1) { fprintf(mesg, "Retry with option -qF to truncate, with -FF to attempt full recovery\n"); ZIPERR(ZE_FORM, NULL); } } cenbeg = s; zcomlen = 0; if (zipbeg && noisy) fprintf(mesg, "%s: adjusting offsets for a preamble of %lu bytes\n", zipfile, zipbeg); /* Done with zip file for now */ fclose(f); /* If one or more files, sort by name */ if (zcount) { if ((x = zsort = (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) == NULL) return ZE_MEM; for (z = zfiles; z != NULL; z = z->nxt) *x++ = z; qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp); } } return ZE_OK;}#endif /* !UTIL *//* * readzipfile starts searching for the End Signature at the end of the file * The End Signature points to the Central Directory Signature which points * to the Local Directory Signature * XXX probably some more consistency checks are needed */int readzipfile()/* The name of the zip file is pointed to by the global "zipfile". The globals zfiles, zcount, zcomlen, zcomment, and zsort are filled in. Return an error code in the ZE_ class.*/{ char b[CENHEAD]; /* buffer for central headers */ FILE *f; /* zip file */ ush flg; /* general purpose bit flag */ int m; /* mismatch flag */ extent n; /* length of name */ struct zlist far * far *x; /* pointer last entry's link */ struct zlist far *z; /* current zip entry structure */ char *t; /* temporary pointer */ char far *u; /* temporary variable */ int found; char *buf; /* temp buffer for reading zipfile */ long deltaoff;#ifndef UTIL if (fix && !adjust) return readzipfile2();#endif /* Initialize zip file info */ zipbeg = 0; zfiles = NULL; /* Points to first header */ zcomlen = 0; /* zip file comment length */ /* 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; } } if ((f = fopen(zipfile, FOPR)) != NULL)#else /* !VMS */ if (zipfile != NULL && *zipfile && strcmp(zipfile, "-") && (f = fopen(zipfile, FOPR)) != NULL)#endif /* ?VMS */ { buf = malloc(4096 + 4); if (buf == NULL) return ZE_MEM;#ifdef HANDLE_AMIGA_SFX amiga_sfx_offset = (fread(buf, 1, 4, f) == 4 && LG(buf) == 0xF3030000); /* == 1 if this file is an Amiga executable (presumably UnZipSFX) */#endif found = 0; t = &buf[4096]; t[1] = '\0'; t[2] = '\0'; t[3] = '\0'; if (fseek(f, -4096L, SEEK_END) == 0) { zipbeg = (ulg) (ftell(f) + 4096L); while (!found && zipbeg >= 4096) { zipbeg -= 4096L; buf[4096] = t[1]; buf[4097] = t[2]; buf[4098] = t[3];/* * XXX error check ?? */ fread(buf, 1, 4096, f); fseek(f, -8192L, SEEK_CUR); t = &buf[4095];/* * XXX far pointer arithmetic in DOS */ while (t >= buf) { /* Check for ENDSIG ("PK\5\6" in ASCII) */ if (LG(t) == ENDSIG) { found = 1;/* * XXX error check ?? * XXX far pointer arithmetic in DOS */ zipbeg += (ulg) (t - buf); fseek(f, (long) zipbeg + 4L, SEEK_SET); break; } --t; } } } else zipbeg = 4096L;/* * XXX warn: garbage at the end of the file ignored */ if (!found && zipbeg > 0) { size_t s; rewind(f); s = fread(buf, 1, (size_t) zipbeg, f); buf[s] = t[1]; buf[s + 1] = t[2]; buf[s + 2] = t[3]; t = &buf[s - 1];/* * XXX far pointer comparison in DOS */ while (t >= buf) { /* Check for ENDSIG ("PK\5\6" in ASCII) */ if (LG(t) == ENDSIG) { found = 1;/* * XXX far pointer arithmetic in DOS */ zipbeg = (ulg) (t - buf); fseek(f, (long) zipbeg + 4L, SEEK_SET); break; } --t; } } free(buf); if (!found) { zipwarn("missing end signature--probably not a zip file (did you", ""); zipwarn("remember to use binary mode when you transferred it?)", ""); return ZE_FORM; } /* Read end header */ if (fread(b, ENDHEAD, 1, f) != 1) return ferror(f) ? ZE_READ : ZE_EOF; if (SH(ENDDSK + b) || SH(ENDBEG + b) || SH(ENDSUB + b) != SH(ENDTOT + b)) zipwarn("multiple disk information ignored", ""); zcomlen = SH(ENDCOM + b); if (zcomlen) { if ((zcomment = malloc(zcomlen)) == NULL) return ZE_MEM; if (fread(zcomment, zcomlen, 1, f) != 1) { free((zvoid *)zcomment); zcomment = NULL; return ferror(f) ? ZE_READ : ZE_EOF; }#ifdef EBCDIC if (zcomment) memtoebc(zcomment, zcomment, zcomlen);#endif /* EBCDIC */ }/* * XXX assumes central header immediately precedes end header */ cenbeg = zipbeg - LG(ENDSIZ + b); deltaoff = adjust ? cenbeg - LG(b + ENDOFF) : 0L; if (fseek(f, cenbeg, SEEK_SET) != 0) { perror("fseek"); return ZE_FORM; /* XXX */ } x = &zfiles; /* first link */ zcount = 0; /* number of files */ if (fread(b, 4, 1, f) != 1) return ferror(f) ? ZE_READ : ZE_EOF; while (LG(b) == CENSIG) { /* Read central header. The portion of the central header that should be in common with local header is read raw, for later comparison. (this requires that the offset of ext in the zlist structure be greater than or equal to LOCHEAD) */ if (fread(b, CENHEAD, 1, f) != 1) return ferror(f) ? ZE_READ : ZE_EOF; if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) return ZE_MEM; z->vem = SH(CENVEM + b); for (u = (char far *)(&(z->ver)), n = 0; n < (CENNAM-CENVER); n++) u[n] = b[CENVER + n]; z->nam = SH(CENNAM + b); /* used before comparing cen vs. loc */ z->cext = SH(CENEXT + b); /* may be different from z->ext */ z->com = SH(CENCOM + b); z->dsk = SH(CENDSK + b); z->att = SH(CENATT + b); z->atx = LG(CENATX + b); z->off = LG(CENOFF + b) + deltaoff; z->dosflag = (z->vem & 0xff00) == 0; /* Initialize all fields pointing to malloced data to NULL */ z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL; /* Link into list */ *x = z; z->nxt = NULL; x = &z->nxt; /* Read file name, extra field and comment field */ if (z->nam == 0) { 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?