📄 unzip.c
字号:
/* unzip.c -- IO on .zip files using zlib
Version 0.15 beta, Mar 19th, 1998,
Read unzip.h for more info
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zlib.h"
#include "unzip.h"
#ifdef STDC
# include <stddef.h>
# include <string.h>
# include <stdlib.h>
#endif
#ifdef NO_ERRNO_H
extern int errno;
#else
# include <errno.h>
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
!defined(CASESENSITIVITYDEFAULT_NO)
#define CASESENSITIVITYDEFAULT_NO
#endif
#ifndef UNZ_BUFSIZE
#define UNZ_BUFSIZE (16384)
#endif
#ifndef UNZ_MAXFILENAMEINZIP
#define UNZ_MAXFILENAMEINZIP (256)
#endif
#ifndef ALLOC
# define ALLOC(size) (malloc(size))
#endif
#ifndef TRYFREE
# define TRYFREE(p) {if (p) free(p);}
#endif
#define SIZECENTRALDIRITEM (0x2e)
#define SIZEZIPLOCALHEADER (0x1e)
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
/* unz_file_info_interntal contain internal info about a file in zipfile*/
typedef struct unz_file_info_internal_s {
uLong offset_curfile;/* relative offset of local header 4 bytes */
} unz_file_info_internal;
/* file_in_zip_read_info_s contain internal information about a file in zipfile,
when reading and decompress it */
typedef struct {
char *read_buffer; /* internal buffer for compressed data */
z_stream stream; /* zLib stream structure for inflate */
uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
uLong stream_initialised; /* flag set if stream structure is initialised*/
uLong offset_local_extrafield;/* offset of the local extra field */
uInt size_local_extrafield;/* size of the local extra field */
uLong pos_local_extrafield; /* position in the local extra field in read*/
uLong crc32; /* crc32 of all data uncompressed */
uLong crc32_wait; /* crc32 we must obtain after decompress all */
uLong rest_read_compressed; /* number of byte to be decompressed */
uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
FILE* file; /* io structore of the zipfile */
uLong compression_method; /* compression method (0==store) */
uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
} file_in_zip_read_info_s;
/* unz_s contain internal information about the zipfile
*/
typedef struct {
FILE* file; /* io structore of the zipfile */
unz_global_info gi; /* public global information */
uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
uLong num_file; /* number of the current file in the zipfile*/
uLong pos_in_central_dir; /* pos of the current file in the central dir*/
uLong current_file_ok; /* flag about the usability of the current file*/
uLong central_pos; /* position of the beginning of the central dir*/
uLong size_central_dir; /* size of the central directory */
uLong offset_central_dir; /* offset of start of central directory with
respect to the starting disk number */
unz_file_info cur_file_info; /* public info about the current file in zip*/
unz_file_info_internal cur_file_info_internal; /* private info about it*/
file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
file if we are decompressing it */
} unz_s;
/* ===========================================================================
Read a byte from a gz_stream; update next_in and avail_in. Return EOF
for end of file.
IN assertion: the stream s has been sucessfully opened for reading.
*/
local int unzlocal_getShort(FILE *fin,uLong *pi) {
unsigned short c;
int err = fread(&c, 2, 1, fin);
if (err==1) {
*pi = (uLong)c;
return UNZ_OK;
} else {
if (ferror(fin)) return UNZ_ERRNO;
else return UNZ_EOF;
}
}
local int unzlocal_getLong(FILE *fin,uLong *pi) {
uLong c;
int err = fread(&c, 4, 1, fin);
if (err==1) {
*pi = (uLong)c;
return UNZ_OK;
} else {
if (ferror(fin)) return UNZ_ERRNO;
else return UNZ_EOF;
}
}
#define BUFREADCOMMENT (0x400)
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
local uLong unzlocal_SearchCentralDir(FILE *fin) {
unsigned char* buf;
uLong uSizeFile;
uLong uBackRead;
uLong uMaxBack=0xffff; /* maximum size of global comment */
uLong uPosFound=0;
if (fseek(fin,0,SEEK_END) != 0) return 0;
uSizeFile = ftell( fin );
if (uMaxBack>uSizeFile) uMaxBack = uSizeFile;
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (!buf) return 0;
uBackRead = 4;
while (uBackRead<uMaxBack) {
uLong uReadSize,uReadPos ;
int i;
if (uBackRead+BUFREADCOMMENT>uMaxBack) uBackRead = uMaxBack;
else uBackRead+=BUFREADCOMMENT;
uReadPos = uSizeFile-uBackRead ;
uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
(BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
if (fseek(fin,uReadPos,SEEK_SET)!=0) break;
if (fread(buf,(uInt)uReadSize,1,fin)!=1) break;
for (i=(int)uReadSize-3; (i--)>0;)
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) {
uPosFound = uReadPos+i;
break;
}
if (uPosFound!=0) break;
}
TRYFREE(buf);
return uPosFound;
}
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
"zlib/zlib109.zip".
If the zipfile cannot be opened (file don't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
*/
extern unzFile ZEXPORT unzOpen (const char *path) {
unz_s us;
unz_s *s;
uLong central_pos,uL;
FILE * fin ;
uLong number_disk; /* number of the current dist, used for
spaning ZIP, unsupported, always 0*/
uLong number_disk_with_CD; /* number the the disk with central dir, used
for spaning ZIP, unsupported, always 0*/
uLong number_entry_CD; /* total number of entries in
the central dir
(same than number_entry on nospan) */
int err=UNZ_OK;
fin=fopen(path,"rb");
if (!fin) return NULL;
central_pos = unzlocal_SearchCentralDir(fin);
if (!central_pos) err=UNZ_ERRNO;
if (fseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO;
/* the signature, already checked */
if (unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO;
/* number of this disk */
if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO;
/* number of the disk with the start of the central directory */
if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO;
/* total number of entries in the central dir on this disk */
if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO;
/* total number of entries in the central dir */
if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO;
if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE;
/* size of the central directory */
if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO;
/* offset of start of central directory with respect to the
starting disk number */
if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO;
/* zipfile comment length */
if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO;
if ((central_pos<us.offset_central_dir+us.size_central_dir) && (err==UNZ_OK)) err=UNZ_BADZIPFILE;
if (err!=UNZ_OK) {
fclose(fin);
return NULL;
}
us.file=fin;
us.byte_before_the_zipfile = central_pos - (us.offset_central_dir+us.size_central_dir);
us.central_pos = central_pos;
us.pfile_in_zip_read = NULL;
s=(unz_s*)ALLOC(sizeof(unz_s));
*s=us;
unzGoToFirstFile((unzFile)s);
return (unzFile)s;
}
/*
Close a ZipFile opened with unzipOpen.
If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzClose (unzFile file) {
unz_s* s;
if (!file) return UNZ_PARAMERROR;
s=(unz_s*)file;
if (s->pfile_in_zip_read) unzCloseCurrentFile(file);
fclose(s->file);
TRYFREE(s);
return UNZ_OK;
}
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info) {
unz_s* s;
if (!file) return UNZ_PARAMERROR;
s=(unz_s*)file;
*pglobal_info=s->gi;
return UNZ_OK;
}
/*
Get Info about the current file in the zipfile, with internal only info
*/
local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
unz_file_info *pfile_info,
unz_file_info_internal
*pfile_info_internal,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
unz_file_info *pfile_info,
unz_file_info_internal *pfile_info_internal,
char *szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize,
char *szComment, uLong commentBufferSize) {
unz_s* s;
unz_file_info file_info;
unz_file_info_internal file_info_internal;
int err=UNZ_OK;
uLong uMagic;
long lSeek=0;
if (!file) return UNZ_PARAMERROR;
s=(unz_s*)file;
if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) err=UNZ_ERRNO;
/* we check the magic */
if (err==UNZ_OK)
if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO;
else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE;
fread(&file_info, sizeof(file_info)-2*4, 1, s->file); // 2*4 is the size of 2 my vars
if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO;
file_info.offset = file_info_internal.offset_curfile;
file_info.c_offset = s->pos_in_central_dir;
lSeek+=file_info.size_filename;
if ((err==UNZ_OK) && (szFileName)) {
uLong uSizeRead ;
if (file_info.size_filename<fileNameBufferSize) {
*(szFileName+file_info.size_filename)='\0';
uSizeRead = file_info.size_filename;
} else uSizeRead = fileNameBufferSize;
if ((file_info.size_filename>0) && (fileNameBufferSize>0))
if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO;
lSeek -= uSizeRead;
}
if ((err==UNZ_OK) && (extraField)) {
uLong uSizeRead ;
if (file_info.size_file_extra<extraFieldBufferSize) uSizeRead = file_info.size_file_extra;
else uSizeRead = extraFieldBufferSize;
if (lSeek!=0)
if (fseek(s->file,lSeek,SEEK_CUR)==0) lSeek=0;
else err=UNZ_ERRNO;
if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO;
lSeek += file_info.size_file_extra - uSizeRead;
}
else lSeek+=file_info.size_file_extra;
if ((err==UNZ_OK) && (szComment)) {
uLong uSizeRead ;
if (file_info.size_file_comment<commentBufferSize) {
*(szComment+file_info.size_file_comment)='\0';
uSizeRead = file_info.size_file_comment;
} else uSizeRead = commentBufferSize;
if (lSeek!=0)
if (fseek(s->file,lSeek,SEEK_CUR)==0) lSeek=0;
else err=UNZ_ERRNO;
if ((file_info.size_file_comment>0) && (commentBufferSize>0))
if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO;
lSeek+=file_info.size_file_comment - uSizeRead;
} else lSeek+=file_info.size_file_comment;
if ((err==UNZ_OK) && (pfile_info)) *pfile_info=file_info;
if ((err==UNZ_OK) && (pfile_info_internal)) *pfile_info_internal=file_info_internal;
return err;
}
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem.
*/
extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
unz_file_info *pfile_info,
char *szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize,
char *szComment, uLong commentBufferSize) {
return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
szFileName,fileNameBufferSize,
extraField,extraFieldBufferSize,
szComment,commentBufferSize);
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -