📄 unzip.c
字号:
/* ==========================================================================
Unzip.cpp
Interface into the inflation (decompression) of compressed archive files.
These functions (as the name unzip.cpp implies) provide methods for
extracting data from files created with either Phil Katz's PKZIP or
Mark Adlers (GCC) unzip.
Originally, this file was kept as similiar to the original dounzip.c
that is part of the gcc unzip distribution. The idea being that anyone
could diff this file versus that file and see the changes that were
made. Unfortunately, the number have changes have become so great that
there would be far more differences than similarities, making this
process of little benefit.
Inflate.cpp, inflate.h and unzip.h are exactly as they are in the
gcc distribution. **Touch them if you dare**.
*06/12/96 - not any more, inflate is now completely thread safe, and
therefore, looks nothing like it did before (not that its good - but
it is better)*
NOTE: MSVC users - don't even bother trying to 'Update Dependencies'.
Uggh! 06/30/96 - This should work now
Created Mark Adler & Jean-loup Gailly (GCC)
Modified Roger Fujii (STTNG:AFU)
Big Purge Kevin Ray (RESMGR)
RESMGR Library component unzip.cpp (ver: 2.05 released 03/26/97)
========================================================================== */
#include <ctype.h>
#include <fcntl.h>
#include "lists.h"
#include "unzip.h" /* includes, typedefs, macros, etc. */
#include "resmgr.h"
#include "omni.h"
#include <assert.h>
#ifdef USE_SH_POOLS
#undef MemFree
#undef MemFreePtr
#undef MemMalloc
#include "Smartheap\Include\smrtheap.h"
extern MEM_POOL gResmgrMemPool;
#endif
/* -------------------------------------------------------------------------
S T A T I C D A T A
------------------------------------------------------------------------- */
static char seeklocked = FALSE;
int UNZIP_ERROR = 0; /* errno */
/* initialize signatures at runtime so unzip
executable won't look like a zipfile */
static char near central_hdr_sig[5] = { 0, '\113', '\001', '\002' };
static char near local_hdr_sig[5] = { 0, '\113', '\003', '\004' };
static char near end_central_sig[5] = { 0, '\113', '\005', '\006' };
/* -------------------------------------------------------------------------
L O C A L P R O T O T Y P E S
------------------------------------------------------------------------- */
int extract_or_test_member( int method, long ucsize, COMPRESSED_FILE * cmp ); /* return PK-type error code */
static int process_cdir_file_hdr( cdir_file_hdr * crec, ARCHIVE * arc );
static int do_string( unsigned int len, int option, char * filename, ARCHIVE * arc );
static int get_cdir_file_hdr( cdir_file_hdr * crec, ARCHIVE * arc );
int archive_size( ARCHIVE * arc );
int unzip_seek( LONGINT val, ARCHIVE * arc );
int process_local_file_hdr( local_file_hdr * lrec, char * buffer );
#define CREATE_LOCK(a) CreateMutex( NULL, FALSE, a );
#define REQUEST_LOCK(a) WaitForSingleObject(a, INFINITE);
#define RELEASE_LOCK(a) ReleaseMutex(a);
#define DESTROY_LOCK(a) CloseHandle(a);
/* -------------------------------------------------------------------------
E X T E R N A L P R O T O T Y P E S & D A T A
------------------------------------------------------------------------- */
extern HASH_ENTRY * hash_add( struct _finddata_t * data, HASH_TABLE * table );
extern HASH_ENTRY * hash_find( const char * name, HASH_TABLE * hsh ); /* find an entry within a hash table */
extern HASH_TABLE * hash_create( int size, char * filename );
extern int hash_resize( HASH_TABLE * table );
extern char * res_fullpath( char * abs_buffer, const char * rel_buffer, int maxlen );
extern HASH_TABLE * GLOBAL_HASH_TABLE;
extern LIST * GLOBAL_PATH_LIST;
extern char * GLOBAL_SEARCH_PATH[];
extern int GLOBAL_SEARCH_INDEX;
extern int RES_DEBUG_ERRNO;
#if( RES_DEBUG_VERSION )
void
_say_error( int error, const char * msg, int line, const char * filename );
# define SAY_ERROR(a,b) _say_error((a),(b), __LINE__, __FILE__ )
#else
# define SAY_ERROR(a,b) {RES_DEBUG_ERRNO=(a);}
#endif /* RES_DEBUG_VERSION */
/* -------------------------------------------------------------------------
C O M P I L E R D E F I N I T I O N S
------------------------------------------------------------------------- */
#define MAKE_WORD(a) makeword( &byterec[(a)] );
#define MAKE_LONG(a) makelong( &byterec[(a)] );
#define WriteError(buf, len, strm) memcpy((void *)((int)arc -> out_buffer + arc -> out_count), buf, len); arc -> out_count += len;
#ifdef SFX
# define UNKN_COMPR \
(crec.compression_method!=STORED && crec.compression_method!=DEFLATED)
#else
# define UNKN_COMPR \
(crec.compression_method>IMPLODED && crec.compression_method!=DEFLATED)
#endif
#define UNZIP_LSEEK(a,b) unzip_seek(a,b)
/* =======================================================
FUNCTION: archive_create
PURPOSE: Main interface into the unzip functions.
archive_create opens a compressed
archive file and adds the contents into
the hash table at the point specified.
PARAMS: Ptr to a directory to attach the
archive into, ptr to a complete filename
of the archive file, ptr to the hash
table for the attach point.
RETURNS: Ptr to the create archive structure.
======================================================= */
ARCHIVE * archive_create( const char * attach_point, const char * filename, HASH_TABLE * table, int replace_flag )
{
ARCHIVE * arc;
HASH_ENTRY * entry;
struct _finddata_t data; /* for hash_find */
struct _finddata_t info;
char sig[5];
char vol_was;
int dir_was;
int error = 0,
error_in_archive = 0,
i, len;
char path_was[_MAX_PATH],
path[_MAX_PATH];
char * fname; /* used to truncate path from filename */
int path_idx;
ecdir_rec ecrec; /* used in unzip.c, extract.c */
// int filnum=(-1);
ush members_remaining;//,
// num_skipped = 0,
// num_bad_pwd = 0;
char curfilename[FILNAMSIZ];
cdir_file_hdr crec; /* used in unzip.c, extract.c, misc.c */
#ifdef USE_SH_POOLS
arc = (ARCHIVE *)MemAllocPtr( gResmgrMemPool, sizeof(ARCHIVE), 0 );
#else
arc = (ARCHIVE *)MemMalloc( sizeof(ARCHIVE), filename );
#endif
if( !arc ) {
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL );
}
strcpy( arc -> name, filename );
arc -> lock = CREATE_LOCK( "Archive" );
/*---------------------------------------------------------------------------
Start by constructing the various PK signature strings.
---------------------------------------------------------------------------*/
local_hdr_sig[0] = '\120'; /* ASCII 'P', */
central_hdr_sig[0] = '\120';
end_central_sig[0] = '\120'; /* not EBCDIC */
strcpy( path_was, attach_point );
#ifdef USE_SH_POOLS
arc -> tmp_slide = (uch *)MemAllocPtr( gResmgrMemPool, UNZIP_SLIDE_SIZE, 0 );
#else
arc -> tmp_slide = (uch *)MemMalloc( UNZIP_SLIDE_SIZE, "Slide" );
#endif
if( arc -> tmp_slide == NULL ) {
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL ); /* 4 extra for hold[] (below) */
}
{
struct stat statbuf;
if( SSTAT(filename, &statbuf) || (error = S_ISDIR(statbuf.st_mode)) != 0)
{
ResCheckMedia( toupper(filename[0]) - 'A' ); /* see if media has been swapped */
#ifdef USE_SH_POOLS
MemFreePtr( arc -> tmp_slide );
MemFreePtr( arc );
#else
MemFree( arc -> tmp_slide );
MemFree( arc );
#endif
UNZIP_ERROR = RES_ERR_UNKNOWN;
return( NULL );
}
arc -> length = statbuf.st_size;
}
if(( arc -> os_handle = _open( filename, O_RDONLY | O_BINARY )) < 0 )
{
ResCheckMedia( toupper(filename[0]) - 'A' ); /* see if media has been swapped */
#ifdef USE_SH_POOLS
MemFreePtr( arc -> tmp_slide );
MemFreePtr( arc );
#else
MemFree( arc -> tmp_slide );
MemFree( arc );
#endif
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL );
}
res_fullpath( path, filename, _MAX_PATH );
arc -> volume = (char)(toupper( path[0] ) - 'A');
arc -> start_buffer = 0;
// Use 2048 size buffer for now, so we don't break things
// But Input buffer is set to INPUTBUFSIZE >> 2048 + 4
arc -> tmp_in_size = UNZIP_BUFFER_SIZE;
#ifdef USE_SH_POOLS
if(( arc -> tmp_in_buffer = (uch *)MemAllocPtr( gResmgrMemPool, INPUTBUFSIZE, 0 )) == NULL )
{
_close( arc -> os_handle );
MemFreePtr( arc -> tmp_slide );
MemFreePtr( arc );
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL );
}
#else
if(( arc -> tmp_in_buffer = (uch *)MemMalloc( INPUTBUFSIZE, "input buffer" )) == NULL )
{
_close( arc -> os_handle );
MemFree( arc -> tmp_slide );
MemFree( arc );
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL );
}
#endif
arc -> tmp_hold = (uch *)(arc -> tmp_in_buffer + arc -> tmp_in_size); /* to check for boundary-spanning signatures */
arc -> tmp_in_ptr = (uch *)(arc -> tmp_in_buffer);
#if( RES_PREDETERMINE_SIZE )
int sz;
sz = archive_size( arc );
/* printf( "archive size: %d\n", sz );*/
if( ARCHIVE_TABLE_SIZE < (sz>>1)) {
table -> num_entries = sz;
if( !hash_resize( table )) {
_close( arc -> os_handle );
#ifdef USE_SH_POOLS
MemFreePtr( arc -> tmp_in_buffer );
MemFreePtr( arc -> tmp_slide );
MemFreePtr( arc );
#else
MemFree( arc -> tmp_in_buffer );
MemFree( arc -> tmp_slide );
MemFree( arc );
#endif
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL );
}
}
#endif /*RES_PREDETERMINE_SIZE */
//****** (arc -> len) ? 66000L ? *****//
if(( ((error_in_archive = find_end_central_dir(MIN((arc -> length),66000L), &ecrec, arc)) != 0 )))
{
_close( arc -> os_handle );
#ifdef USE_SH_POOLS
MemFreePtr( arc -> tmp_in_buffer );
MemFreePtr( arc -> tmp_slide );
MemFreePtr( arc );
#else
MemFree( arc -> tmp_in_buffer );
MemFree( arc -> tmp_slide );
MemFree( arc );
#endif
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL );
}
/*-----------------------------------------------------------------------
Compensate for missing or extra bytes, and seek to where the start
of central directory should be. If header not found, uncompensate
and try again (necessary for at least some Atari archives created
with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
----------------------------------------------------------------------- */
//LSEEK( ecrec.offset_start_central_directory );
if( UNZIP_LSEEK( ecrec.offset_start_central_directory, arc )) {
_close( arc -> os_handle );
#ifdef USE_SH_POOLS
MemFreePtr( arc -> tmp_in_buffer );
MemFreePtr( arc -> tmp_slide );
MemFreePtr( arc );
#else
MemFree( arc -> tmp_in_buffer );
MemFree( arc -> tmp_slide );
MemFree( arc );
#endif
UNZIP_ERROR = RES_ERR_NO_MEMORY;
return( NULL );
}
/* -----------------------------------------------------------------------
Seek to the start of the central directory one last time, since we
have just read the first entry's signature bytes; then list, extract
or test member files as instructed, and close the zipfile.
-----------------------------------------------------------------------*/
/* ---------------------------------------------------------------------------
The basic idea of this function is as follows. Since the central di-
rectory lies at the end of the zipfile and the member files lie at the
beginning or middle or wherever, it is not very desirable to simply
read a central directory entry, jump to the member and extract it, and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -