📄 unzip.c
字号:
/* unzip.c -- IO for uncompress .zip files using zlib
Version 1.01, May 8th, 2004
Copyright (C) 1998-2004 Gilles Vollant
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
/* compile with -Dlocal if your debugger can't find static symbols */
#ifndef CASESENSITIVITYDEFAULT_NO
#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
#define CASESENSITIVITYDEFAULT_NO
#endif
#endif
#ifndef UNZ_BUFSIZE
#define UNZ_BUFSIZE (32768)
#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)
/* unz_file_info_interntal contain internal info about a file in zipfile*/
typedef struct unz_file_info_internal_s
{
DWORD 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 */
DWORD pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
DWORD stream_initialised; /* flag set if stream structure is initialised*/
DWORD offset_local_extrafield; /* offset of the local extra field */
DWORD size_local_extrafield; /* size of the local extra field */
DWORD pos_local_extrafield; /* position in the local extra field in read*/
DWORD crc32; /* crc32 of all data uncompressed */
DWORD crc32_wait; /* crc32 we must obtain after decompress all */
DWORD rest_read_compressed; /* number of byte to be decompressed */
DWORD rest_read_uncompressed; /*number of byte to be obtained after decomp*/
zlib_filefunc_def z_filefunc;
void *filestream; /* io structore of the zipfile */
DWORD compression_method; /* compression method (0==store) */
DWORD byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/
int raw;
} file_in_zip_read_info_s;
/* unz_s contain internal information about the zipfile
*/
typedef struct
{
zlib_filefunc_def z_filefunc;
void *filestream; /* io structore of the zipfile */
unz_global_info gi; /* public global information */
DWORD byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/
DWORD num_file; /* number of the current file in the zipfile*/
DWORD pos_in_central_dir; /* pos of the current file in the central dir*/
DWORD current_file_ok; /* flag about the usability of the current file*/
DWORD central_pos; /* position of the beginning of the central dir*/
DWORD size_central_dir; /* size of the central directory */
DWORD 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 */
int encrypted;
#ifndef NOUNCRYPT
DWORD keys[3]; /* keys defining the pseudo-random sequence */
const DWORD *pcrc_32_tab;
#endif
} unz_s;
#ifndef NOUNCRYPT
#include "crypt.h"
#endif
/* ===========================================================================
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.
*/
static int unzlocal_getByte(const zlib_filefunc_def *pzlib_filefunc_def, void *filestream, int *pi)
{
BYTE c;
int err = (int)ZREAD(*pzlib_filefunc_def, filestream, &c, 1);
if (err == 1)
{
*pi = (int)c;
return UNZ_OK;
}
else
{
if (ZERROR(*pzlib_filefunc_def, filestream))
{
return UNZ_ERRNO;
}
else
{
return UNZ_EOF;
}
}
}
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
static int unzlocal_getShort(const zlib_filefunc_def *pzlib_filefunc_def, void *filestream, DWORD *pX)
{
DWORD x;
int i;
int err;
err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i);
x = (DWORD)i;
if (err == UNZ_OK)
{
err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i);
}
x += ((DWORD)i) << 8;
if (err == UNZ_OK)
{
*pX = x;
}
else
{
*pX = 0;
}
return err;
}
//-------------------------------------------------------------------------
static int unzlocal_getLong(const zlib_filefunc_def *pzlib_filefunc_def, void *filestream, DWORD *pX)
{
DWORD x;
int i;
int err;
err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i);
x = (DWORD)i;
if (err == UNZ_OK)
{
err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i);
}
x += ((DWORD)i) << 8;
if (err == UNZ_OK)
{
err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i);
}
x += ((DWORD)i) << 16;
if (err == UNZ_OK)
{
err = unzlocal_getByte(pzlib_filefunc_def, filestream, &i);
}
x += ((DWORD)i) << 24;
if (err == UNZ_OK)
{
*pX = x;
}
else
{
*pX = 0;
}
return err;
}
//-------------------------------------------------------------------------
#ifdef CASESENSITIVITYDEFAULT_NO
#define CASESENSITIVITYDEFAULTVALUE 2
#else
#define CASESENSITIVITYDEFAULTVALUE 1
#endif
#ifndef STRCMPCASENOSENTIVEFUNCTION
#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
#endif
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
or strcasecmp)
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
(like 1 on Unix, 2 on Windows)
*/
/*
extern int ZEXPORT unzStringFileNameCompare(const char *fileName1, const char *fileName2, int iCaseSensitivity)
{
if (iCaseSensitivity == 0)
{
iCaseSensitivity = CASESENSITIVITYDEFAULTVALUE;
}
if (iCaseSensitivity == 1)
{
return strcmp(fileName1, fileName2);
}
return stricmp(fileName1, fileName2);
}
*/
//-------------------------------------------------------------------------
#ifndef BUFREADCOMMENT
#define BUFREADCOMMENT (0x400)
#endif
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
static DWORD unzlocal_SearchCentralDir(const zlib_filefunc_def *pzlib_filefunc_def, void *filestream)
{
BYTE *buf;
DWORD uSizeFile;
DWORD uBackRead;
DWORD uMaxBack = 0xffff; /* maximum size of global comment */
DWORD uPosFound = 0;
if (ZSEEK(*pzlib_filefunc_def, filestream, 0, SEEK_END) != 0)
{
return 0;
}
uSizeFile = ZTELL(*pzlib_filefunc_def, filestream);
if (uMaxBack > uSizeFile)
{
uMaxBack = uSizeFile;
}
buf = (BYTE*)ALLOC(BUFREADCOMMENT + 4);
if (buf == NULL)
{
return 0;
}
uBackRead = 4;
while (uBackRead < uMaxBack)
{
DWORD 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 (ZSEEK(*pzlib_filefunc_def, filestream, uReadPos, SEEK_SET) != 0)
{
break;
}
if (ZREAD(*pzlib_filefunc_def, filestream, buf, uReadSize) != uReadSize)
{
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\\zlib114.zip" or on an Unix computer
"zlib/zlib114.zip".
If the zipfile cannot be opened (file doesn'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 unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def)
{
unz_s us;
unz_s *s;
DWORD central_pos, uL;
DWORD number_disk; /* number of the current dist, used for
spaning ZIP, unsupported, always 0*/
DWORD number_disk_with_CD; /* number the the disk with central dir, used
for spaning ZIP, unsupported, always 0*/
DWORD number_entry_CD; /* total number of entries in
the central dir
(same than number_entry on nospan) */
int err = UNZ_OK;
if (pzlib_filefunc_def == NULL)
{
fill_fopen_filefunc(&us.z_filefunc);
}
else
{
us.z_filefunc = *pzlib_filefunc_def;
}
us.filestream = (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
if (us.filestream == NULL)
{
return NULL;
}
central_pos = unzlocal_SearchCentralDir(&us.z_filefunc, us.filestream);
if (central_pos == 0)
{
err = UNZ_ERRNO;
}
if (ZSEEK(us.z_filefunc, us.filestream, central_pos, SEEK_SET) != 0)
{
err = UNZ_ERRNO;
}
/* the signature, already checked */
if (unzlocal_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK)
{
err = UNZ_ERRNO;
}
/* number of this disk */
if (unzlocal_getShort(&us.z_filefunc, us.filestream, &number_disk) != UNZ_OK)
{
err = UNZ_ERRNO;
}
/* number of the disk with the start of the central directory */
if (unzlocal_getShort(&us.z_filefunc, us.filestream, &number_disk_with_CD) != UNZ_OK)
{
err = UNZ_ERRNO;
}
/* total number of entries in the central dir on this disk */
if (unzlocal_getShort(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK)
{
err = UNZ_ERRNO;
}
/* total number of entries in the central dir */
if (unzlocal_getShort(&us.z_filefunc, us.filestream, &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(&us.z_filefunc, us.filestream, &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(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK)
{
err = UNZ_ERRNO;
}
/* zipfile comment length */
if (unzlocal_getShort(&us.z_filefunc, us.filestream, &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)
{
ZCLOSE(us.z_filefunc, us.filestream);
return NULL;
}
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;
us.encrypted = 0;
s = (unz_s*)ALLOC(sizeof(unz_s));
*s = us;
unzGoToFirstFile((unzFile)s);
return (unzFile)s;
}
//-------------------------------------------------------------------------
extern unzFile ZEXPORT unzOpen(const char *path)
{
return unzOpen2(path, NULL);
}
/*
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 == NULL)
{
return UNZ_PARAMERROR;
}
s = (unz_s*)file;
if (s->pfile_in_zip_read != NULL)
{
unzCloseCurrentFile(file);
}
ZCLOSE(s->z_filefunc, s->filestream);
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 == NULL)
{
return UNZ_PARAMERROR;
}
s = (unz_s*)file;
*pglobal_info = s->gi;
return UNZ_OK;
}
*/
/*
Translate date/time from Dos format to tm_unz (readable more easilty)
*/
static void unzlocal_DosDateToTmuDate(DWORD ulDosDate, tm_unz *ptm)
{
DWORD uDate;
uDate = (DWORD)(ulDosDate >> 16);
ptm->tm_mday = (DWORD)(uDate &0x1f);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -