📄 unzip.c
字号:
unshrink = 0; /* Keep compiler from complaining */
memcpy( cmp -> out_buffer + cmp -> out_count, rawbuf, size );
cmp -> out_count += size;
return( 0 );
}
/* =======================================================
FUNCTION: find_end_central_dir()
PURPOSE: ...
PARAMETERS: Ptr to buffer, size, ...
RETURNS: Error code if any.
======================================================= */
int find_end_central_dir( long searchlen, ecdir_rec *ecrec, ARCHIVE * arc )
{
int i,
numblks,
found = FALSE;
LONGINT tail_len;
ec_byte_rec byterec;
LONGINT real_ecrec_offset,
expect_ecrec_offset;
/*---------------------------------------------------------------------------
Treat case of short zipfile separately.
---------------------------------------------------------------------------*/
if((arc -> length ) <= arc -> tmp_in_size )
{
lseek( arc -> os_handle, 0L, SEEK_SET);
if(( arc -> tmp_in_count = read( arc -> os_handle, (char *)arc -> tmp_in_buffer, (unsigned int)(arc -> length))) == (int)(arc -> length))
{
/* 'P' must be at least 22 bytes from end of zipfile */
for( arc -> tmp_in_ptr = arc -> tmp_in_buffer + (arc -> length - 22);
arc -> tmp_in_ptr >= arc -> tmp_in_buffer;
arc -> tmp_in_ptr = arc -> tmp_in_ptr - 1 /* was: --inptr uggh! */
)
{
// if((native(*((int*)arc -> tmp_in_ptr)) == 'P') &&
// !strncmp((char *)arc -> tmp_in_ptr, end_central_sig, 4)) /* GFG 31/01/98
if(( (*(char*)(arc -> tmp_in_ptr)) == 'P') && !strncmp((char *)arc -> tmp_in_ptr, end_central_sig, 4))
{
arc -> tmp_in_count -= (int)arc -> tmp_in_ptr - (int)arc -> tmp_in_buffer;
found = TRUE;
break;
}
}
}
}
else /* --------------------------------------------------------------------------- */
{ /* Zipfile is longer than inbufsiz: may need to loop. Start with short */
/* block at end of zipfile (if not TOO short). */
/* --------------------------------------------------------------------------- */
if((tail_len = (arc -> length) % arc -> tmp_in_size) > ECREC_SIZE )
{
arc -> start_buffer = lseek( arc -> os_handle, (arc -> length) - tail_len, SEEK_SET );
arc -> tmp_in_count = read( arc -> os_handle, (char *)arc -> tmp_in_buffer, (unsigned int)tail_len );
if( arc -> tmp_in_count != (int)tail_len )
goto fail; /* shut up; it's expedient */
/* 'P' must be at least 22 bytes from end of zipfile */
for( arc -> tmp_in_ptr = arc -> tmp_in_buffer + (tail_len - 22);
arc -> tmp_in_ptr >= arc -> tmp_in_buffer;
arc -> tmp_in_ptr = arc -> tmp_in_ptr - 1
)
{
if(( (*(char*)(arc -> tmp_in_ptr)) == 'P') && !strncmp((char *)arc -> tmp_in_ptr, end_central_sig, 4))
{
arc -> tmp_in_count -= (int)arc -> tmp_in_ptr - (int)arc -> tmp_in_buffer;
found = TRUE;
break;
}
}
/* sig may span block boundary: */
strncpy((char *)arc -> tmp_hold, (char *)arc -> tmp_in_buffer, 3);
}
else
arc -> start_buffer = (arc -> length) - tail_len;
/*-----------------------------------------------------------------------
Loop through blocks of zipfile data, starting at the end and going
toward the beginning. In general, need not check whole zipfile for
signature, but may want to do so if testing.
-----------------------------------------------------------------------*/
numblks = (int)((searchlen - tail_len + (arc -> tmp_in_size - 1)) / arc -> tmp_in_size);
/* ==amount= ==done== ==rounding== =blksiz= */
for( i = 1; !found && (i <= numblks); ++i )
{
arc -> start_buffer -= arc -> tmp_in_size;
lseek( arc -> os_handle, arc -> start_buffer, SEEK_SET );
if(( arc -> tmp_in_count = read(arc -> os_handle,(char *)arc -> tmp_in_buffer, arc -> tmp_in_size )) != arc -> tmp_in_size )
break; /* fall through and fail */
for( arc -> tmp_in_ptr = arc -> tmp_in_buffer + arc -> tmp_in_size - 1;
arc -> tmp_in_ptr >= arc -> tmp_in_buffer;
arc -> tmp_in_ptr = arc -> tmp_in_ptr - 1
)
{
if((*(char *)arc -> tmp_in_ptr == 'P') && !strncmp((char *)arc -> tmp_in_ptr, end_central_sig, 4))
{
arc -> tmp_in_count -= ((int)arc -> tmp_in_ptr - (int)arc -> tmp_in_buffer);
found = TRUE;
break;
}
}
/* sig may span block boundary: */
strncpy( (char *)arc -> tmp_hold, (char *)arc -> tmp_in_buffer, 3 );
}
}
/*---------------------------------------------------------------------------
Searched through whole region where signature should be without finding
it. Print informational message and die a horrible death.
---------------------------------------------------------------------------*/
fail:
if (!found)
{
#ifdef MSWIN
MessageBeep(1);
#endif
// if (qflag || (zipinfo_mode && !hflag))
// fprintf(stderr, "[%s]\n", zipfn);
// fprintf(stderr, "\
// End-of-central-directory signature not found. Either this file is not\n\
// a zipfile, or it constitutes one disk of a multi-part archive. In the\n\
// latter case the central directory and zipfile comment will be found on\n\
// the last disk(s) of this archive.\n\n");
return PK_ERR; /* failed */
}
/*---------------------------------------------------------------------------
Found the signature, so get the end-central data before returning. Do
any necessary machine-type conversions (byte ordering, structure padding
compensation) by reading data into character array and copying to struct.
---------------------------------------------------------------------------*/
real_ecrec_offset = (int)arc -> start_buffer + ((int)arc -> tmp_in_ptr - (int)arc -> tmp_in_buffer);
if( readbuf((char *)byterec, ECREC_SIZE+4, arc ) <= 0 )
return( PK_EOF );
ecrec -> number_this_disk = MAKE_WORD( NUMBER_THIS_DISK );
ecrec -> num_disk_with_start_central_dir = MAKE_WORD( NUM_DISK_WITH_START_CENTRAL_DIR );
ecrec -> num_entries_centrl_dir_ths_disk = MAKE_WORD( NUM_ENTRIES_CENTRL_DIR_THS_DISK );
ecrec -> total_entries_central_dir = MAKE_WORD( TOTAL_ENTRIES_CENTRAL_DIR );
ecrec -> size_central_directory = MAKE_LONG( SIZE_CENTRAL_DIRECTORY );
ecrec -> offset_start_central_directory = MAKE_LONG( OFFSET_START_CENTRAL_DIRECTORY );
ecrec -> zipfile_comment_length = MAKE_WORD( ZIPFILE_COMMENT_LENGTH );
expect_ecrec_offset = ecrec -> offset_start_central_directory + ecrec -> size_central_directory;
return( PK_COOL );
}
/********************************/
/* Function get_cdir_file_hdr() */
/********************************/
static int get_cdir_file_hdr( cdir_file_hdr *crec, ARCHIVE * arc ) /* return PK-type error code */
{
cdir_byte_hdr byterec;
/*---------------------------------------------------------------------------
Read the next central directory entry and do any necessary machine-type
conversions (byte ordering, structure padding compensation--do so by
copying the data from the array into which it was read (byterec) to the
usable struct (crec)).
---------------------------------------------------------------------------*/
if( readbuf((char *)byterec, CREC_SIZE, arc) <= 0 )
return( PK_EOF );
crec->version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
crec->version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
crec->version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
crec->version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
crec->general_purpose_bit_flag = makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
crec->compression_method = makeword(&byterec[C_COMPRESSION_METHOD]);
crec->last_mod_file_time = makeword(&byterec[C_LAST_MOD_FILE_TIME]);
crec->last_mod_file_date = makeword(&byterec[C_LAST_MOD_FILE_DATE]);
crec->crc32 = makelong(&byterec[C_CRC32]);
crec->csize = makelong(&byterec[C_COMPRESSED_SIZE]);
crec->ucsize = makelong(&byterec[C_UNCOMPRESSED_SIZE]);
crec->filename_length = makeword(&byterec[C_FILENAME_LENGTH]);
crec->extra_field_length = makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
crec->file_comment_length = makeword(&byterec[C_FILE_COMMENT_LENGTH]);
crec->disk_number_start = makeword(&byterec[C_DISK_NUMBER_START]);
crec->internal_file_attributes = makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
crec->external_file_attributes = makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */
crec->relative_offset_local_header = makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
return( PK_COOL );
}
/************************/
/* Function do_string() */
/************************/
static int do_string( unsigned int len, int option, char * filename, ARCHIVE * arc ) /* return PK-type error code */
{
int error=PK_OK;
ush extra_len;
/*---------------------------------------------------------------------------
This function processes arbitrary-length (well, usually) strings. Three
options are allowed: SKIP, wherein the string is skipped (pretty logical,
eh?); DISPLAY, wherein the string is printed to standard output after un-
dergoing any necessary or unnecessary character conversions; and FILENAME,
wherein the string is put into the filename[] array after undergoing ap-
propriate conversions (including case-conversion, if that is indicated:
see the global variable pInfo->lcflag). The latter option should be OK,
since filename is now dimensioned at 1025, but we check anyway.
The string, by the way, is assumed to start at the current file-pointer
position; its length is given by len. So start off by checking length
of string: if zero, we're already done.
---------------------------------------------------------------------------*/
if( !len )
return( PK_COOL );
switch (option)
{
/*
* First case: print string on standard output. First set loop vari-
* ables, then loop through the comment in chunks of OUTBUFSIZ bytes,
* converting formats and printing as we go. The second half of the
* loop conditional was added because the file might be truncated, in
* which case comment_bytes_left will remain at some non-zero value for
* all time. outbuf is used as a scratch buffer because it is avail-
* able (we should be either before or in between any file processing).
* [The typecast in front of the MIN() macro was added because of the
* new promotion rules under ANSI C; readbuf() wants an int, but MIN()
* returns a signed long, if I understand things correctly. The proto-
* type should handle it, but just in case...]
*/
case DISPLAY:
case FILENAME:
extra_len = 0;
if( len >= FILNAMSIZ )
{
// fprintf(stderr, "warning: filename too long--truncating.\n");
error = PK_WARN;
extra_len = (ush)( len - FILNAMSIZ + 1 );
len = FILNAMSIZ - 1;
}
if( readbuf(filename, len, arc) <= 0 )
return( PK_EOF );
filename[ len ] = '\0'; /* terminate w/zero: ASCIIZ */
A_TO_N(filename); /* translate string to native */
if( !extra_len ) /* we're done here */
break;
/*
* We truncated the filename, so print what's left and then fall
* through to the SKIP routine.
*/
// fprintf(stderr, "[ %s ]\n", filename);
len = extra_len;
/* =========== FALL THROUGH =========== */
/*
* Third case: skip string, adjusting readbuf's internal variables
* as necessary (and possibly skipping to and reading a new block of
* data).
*/
case SKIP:
if( UNZIP_LSEEK((int)(arc -> start_buffer) + ((int)(arc -> tmp_in_ptr) - (int)(arc -> tmp_in_buffer)) + len, arc ))
return( PK_WARN );
break;
/*
* Fourth case: assume we're at the start of an "extra field"; malloc
* storage for it and read data into the allocated space.
*/
} /* switch */
return( error );
}
/***************************************/
/* Function process_local_file_hdr() */
/***************************************/
int process_local_file_hdr( local_file_hdr * lrec, char * buffer ) /* return PK-type error code */
{
local_byte_hdr byterec;
/*---------------------------------------------------------------------------
Read the next local file header and do any necessary machine-type con-
versions (byte ordering, structure padding compensation--do so by copy-
ing the data from the array into which it was read (byterec) to the
usable struct (lrec)).
---------------------------------------------------------------------------*/
//if( readbuf((char *)byterec, LREC_SIZE) <= 0)
// return PK_EOF;
memcpy( byterec, buffer, LREC_SIZE );
lrec->version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
lrec->version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
lrec->general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
lrec->compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
lrec->last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
lrec->last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
lrec->crc32 = makelong(&byterec[L_CRC32]);
lrec->csize = makelong(&byterec[L_COMPRESSED_SIZE]);
lrec->ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
lrec->filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
lrec->extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
if ((lrec->general_purpose_bit_flag & 8) != 0) {
/* can't trust local header, use central directory
If this is the problem, you should probably extract the
entire zip and then rebuild it. The local header should
always be more reliable than the global, and in your case
it is not (sorry, but you're fucked) */
SAY_ERROR( RES_ERR_BAD_ARCHIVE, "Big problemo, read comment!" );
return( PK_ERR );
}
return( PK_COOL );
} /* end function process_local_file_hdr() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -