Browse Source

filesystem: zip: pk3 support

pull/2/head
Mr0maks 6 years ago
parent
commit
3c0a34926a
  1. 79
      engine/common/filesystem.c
  2. 76
      engine/common/filesystem.h

79
engine/common/filesystem.c

@ -644,7 +644,6 @@ static zipfile_t *FS_AddFileToZip( const char *name, zip_t *zip, fs_offset_t off
static zip_t *FS_LoadZip( const char *zipfile, int *error ) static zip_t *FS_LoadZip( const char *zipfile, int *error )
{ {
zip_header_t header;
int numpackfiles = 0; int numpackfiles = 0;
zip_cdf_header_t header_cdf; zip_cdf_header_t header_cdf;
zip_header_eocd_t header_eocd; zip_header_eocd_t header_eocd;
@ -658,18 +657,18 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
zip->handle = FS_Open( zipfile, "rb", true ); zip->handle = FS_Open( zipfile, "rb", true );
#ifndef _WIN32 #ifndef _WIN32
if ( !zip->handle ) if( !zip->handle )
{ {
const char *fzipfile = FS_FixFileCase( zipfile ); const char *fzipfile = FS_FixFileCase( zipfile );
if (fzipfile != zipfile) if( fzipfile != zipfile )
zip->handle = FS_Open( fzipfile, "rb", true ); zip->handle = FS_Open( fzipfile, "rb", true );
} }
#endif #endif
if ( !zip->handle ) if( !zip->handle )
{ {
Con_Reportf( "%s couldn't open\n", zipfile ); Con_Reportf( "%s couldn't open\n", zipfile );
if (error) if( error )
*error = ZIP_LOAD_COULDNT_OPEN; *error = ZIP_LOAD_COULDNT_OPEN;
Zip_Close( zip ); Zip_Close( zip );
return NULL; return NULL;
@ -678,7 +677,7 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
if( FS_FileLength( zip->handle ) > UINT_MAX ) if( FS_FileLength( zip->handle ) > UINT_MAX )
{ {
Con_Reportf( "%s bigger than 4GB.\n", zipfile ); Con_Reportf( "%s bigger than 4GB.\n", zipfile );
if (error) if( error )
*error = ZIP_LOAD_COULDNT_OPEN; *error = ZIP_LOAD_COULDNT_OPEN;
Zip_Close( zip ); Zip_Close( zip );
return NULL; return NULL;
@ -686,17 +685,17 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
FS_Read( zip->handle, (void *)&signature, sizeof( uint ) ); FS_Read( zip->handle, (void *)&signature, sizeof( uint ) );
if ( signature == ZIP_HEADER_EOCD ) if( signature == ZIP_HEADER_EOCD )
{ {
Con_Reportf( "%s has no files. Ignored.\n", zipfile ); Con_Reportf( "%s has no files. Ignored.\n", zipfile );
if (error) if(error)
*error = ZIP_LOAD_NO_FILES; *error = ZIP_LOAD_NO_FILES;
Zip_Close( zip ); Zip_Close( zip );
return NULL; return NULL;
} }
if ( signature != ZIP_HEADER_LF ) { if( signature != ZIP_HEADER_LF ) {
Con_Reportf( "%s is not a zip file. Ignored.\n", zipfile ); Con_Reportf( "%s is not a zip file. Ignored.\n", zipfile );
if (error) if( error )
*error = ZIP_LOAD_BAD_HEADER; *error = ZIP_LOAD_BAD_HEADER;
Zip_Close( zip ); Zip_Close( zip );
return NULL; return NULL;
@ -711,11 +710,11 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
FS_Seek( zip->handle, filepos, SEEK_SET ); FS_Seek( zip->handle, filepos, SEEK_SET );
FS_Read( zip->handle, (void *)&signature, sizeof( signature ) ); FS_Read( zip->handle, (void *)&signature, sizeof( signature ) );
if (signature == ZIP_HEADER_EOCD) break; if( signature == ZIP_HEADER_EOCD ) break;
filepos -= sizeof( char ); // step back one byte filepos -= sizeof( char ); // step back one byte
} }
if (ZIP_HEADER_EOCD != signature) if( ZIP_HEADER_EOCD != signature )
{ {
Con_Reportf( "Cannot find EOCD in %s. Zip file corrupted.\n", zipfile ); Con_Reportf( "Cannot find EOCD in %s. Zip file corrupted.\n", zipfile );
Zip_Close( zip ); Zip_Close( zip );
@ -736,15 +735,15 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
{ {
FS_Read( zip->handle, (void *)&header_cdf, sizeof( header_cdf ) ); FS_Read( zip->handle, (void *)&header_cdf, sizeof( header_cdf ) );
if (header_cdf.signature != ZIP_HEADER_CDF) if( header_cdf.signature != ZIP_HEADER_CDF )
{ {
Con_Reportf( "CDF signature mismatch in %s. Zip file corrupted.\n", zipfile ); Con_Reportf( "CDF signature mismatch in %s. Zip file corrupted.\n", zipfile );
Zip_Close( zip ); Zip_Close( zip );
return NULL; return NULL;
} }
if ( header_cdf.uncompressed_size && header_cdf.filename_len ) if( header_cdf.uncompressed_size && header_cdf.filename_len )
{ {
char *filename = malloc( header_cdf.filename_len + 1 ); char *filename = malloc( header_cdf.filename_len + 1 );
memset( filename, '\0', header_cdf.filename_len + 1 ); memset( filename, '\0', header_cdf.filename_len + 1 );
@ -759,14 +758,14 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
//Con_Reportf( "ZIP File name: %s .\n", info[numpackfiles].name ); //Con_Reportf( "ZIP File name: %s .\n", info[numpackfiles].name );
numpackfiles++; numpackfiles++;
} }
else else
FS_Seek( zip->handle, header_cdf.filename_len, SEEK_CUR ); FS_Seek( zip->handle, header_cdf.filename_len, SEEK_CUR );
if ( header_cdf.extrafield_len ) if( header_cdf.extrafield_len )
FS_Seek( zip->handle, header_cdf.extrafield_len, SEEK_CUR ); FS_Seek( zip->handle, header_cdf.extrafield_len, SEEK_CUR );
if ( header_cdf.file_commentary_len ) if( header_cdf.file_commentary_len )
FS_Seek( zip->handle, header_cdf.file_commentary_len, SEEK_CUR ); FS_Seek( zip->handle, header_cdf.file_commentary_len, SEEK_CUR );
} }
@ -776,10 +775,10 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
zip->numfiles = 0; zip->numfiles = 0;
zip->files = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( zipfile_t ) * numpackfiles ); zip->files = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( zipfile_t ) * numpackfiles );
for(int i = 0; i < numpackfiles; i++ ) for( int i = 0; i < numpackfiles; i++ )
FS_AddFileToZip( info[i].name, zip, info[i].offset, info[i].size, info[i].compressed_size ); FS_AddFileToZip( info[i].name, zip, info[i].offset, info[i].size, info[i].compressed_size );
if ( error ) *error = ZIP_LOAD_OK; if( error ) *error = ZIP_LOAD_OK;
Mem_Free( info ); Mem_Free( info );
return zip; return zip;
@ -787,7 +786,7 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
void Zip_Close( zip_t *zip ) void Zip_Close( zip_t *zip )
{ {
if ( !zip ) if( !zip )
return; return;
Mem_FreePool( &zip->mempool ); Mem_FreePool( &zip->mempool );
@ -818,19 +817,19 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
FS_Read( search->zip->handle, (void*)&header, sizeof( header ) ); FS_Read( search->zip->handle, (void*)&header, sizeof( header ) );
if (header.signature != ZIP_HEADER_LF) if(header.signature != ZIP_HEADER_LF)
{ {
Con_Reportf( S_ERROR "Zip_LoadFile: %s signature error\n", file->name ); Con_Reportf( S_ERROR "Zip_LoadFile: %s signature error\n", file->name );
return NULL; return NULL;
} }
if (header.compression_flags == ZIP_COMPRESSION_NO_COMPRESSION) if(header.compression_flags == ZIP_COMPRESSION_NO_COMPRESSION)
{ {
if( header.filename_len ) if( header.filename_len )
FS_Seek( search->zip->handle, header.filename_len, SEEK_CUR ); FS_Seek( search->zip->handle, header.filename_len, SEEK_CUR );
if (header.extrafield_len) if( header.extrafield_len )
FS_Seek( search->zip->handle, header.extrafield_len, SEEK_CUR ); FS_Seek( search->zip->handle, header.extrafield_len, SEEK_CUR );
byte *buffer = Mem_Malloc( search->zip->mempool, file->size + 1 ); byte *buffer = Mem_Malloc( search->zip->mempool, file->size + 1 );
@ -855,12 +854,12 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
//Con_Reportf( "ZIP %s load file %s with size %lu\n", search->zip->filename, file->name, file->size ); //Con_Reportf( "ZIP %s load file %s with size %lu\n", search->zip->filename, file->name, file->size );
if (sizeptr) *sizeptr = file->size; if( sizeptr ) *sizeptr = file->size;
return buffer; return buffer;
} }
#ifdef XASH_ZLIB #ifdef XASH_ZLIB
if(header.compression_flags == ZIP_COMPRESSION_DEFLATED) { if( header.compression_flags == ZIP_COMPRESSION_DEFLATED ) {
if( header.filename_len ) if( header.filename_len )
FS_Seek( search->zip->handle, header.filename_len, SEEK_CUR ); FS_Seek( search->zip->handle, header.filename_len, SEEK_CUR );
@ -1059,7 +1058,7 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int
if( already_loaded ) *already_loaded = false; if( already_loaded ) *already_loaded = false;
if( !Q_stricmp( ext, "zip" )) if( !Q_stricmp( ext, "zip" ) || !Q_stricmp( ext, "pk3" ) )
zip = FS_LoadZip( zipfile, &errorcode ); zip = FS_LoadZip( zipfile, &errorcode );
if( zip ) if( zip )
@ -1125,13 +1124,13 @@ void FS_AddGameDirectory( const char *dir, uint flags )
// add any Zip package in the directory // add any Zip package in the directory
for( i = 0; i < list.numstrings; i++ ) for( i = 0; i < list.numstrings; i++ )
{ {
if( !Q_stricmp( COM_FileExtension( list.strings[i] ), "zip" )) if( !Q_stricmp( COM_FileExtension( list.strings[i] ), "zip" ) || !Q_stricmp( COM_FileExtension( list.strings[i] ), "pk3" ))
{ {
Q_sprintf( fullpath, "%s%s", dir, list.strings[i] ); Q_sprintf( fullpath, "%s%s", dir, list.strings[i] );
FS_AddZip_Fullpath( fullpath, NULL, flags ); FS_AddZip_Fullpath( fullpath, NULL, flags );
} }
} }
stringlistfreecontents( &list ); stringlistfreecontents( &list );
FS_AllowDirectPaths( false ); FS_AllowDirectPaths( false );
@ -1231,10 +1230,10 @@ void FS_ClearSearchPath( void )
W_Close( search->wad ); W_Close( search->wad );
} }
if (search->zip) if(search->zip)
{ {
Zip_Close(search->zip); Zip_Close(search->zip);
} }
Mem_Free( search ); Mem_Free( search );
} }
@ -2907,7 +2906,7 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro
{ {
buf = W_LoadFile( path, &filesize, gamedironly ); buf = W_LoadFile( path, &filesize, gamedironly );
if (!buf) if( !buf )
buf = Zip_LoadFile(path, &filesize, gamedironly); buf = Zip_LoadFile(path, &filesize, gamedironly);
} }
@ -3177,7 +3176,7 @@ int FS_FileTime( const char *filename, qboolean gamedironly )
return search->pack->filetime; return search->pack->filetime;
else if( search->wad ) // grab wad filetime else if( search->wad ) // grab wad filetime
return search->wad->filetime; return search->wad->filetime;
else if (search->zip) else if( search->zip )
return search->zip->filetime; return search->zip->filetime;
else if( pack_ind < 0 ) else if( pack_ind < 0 )
{ {

76
engine/common/filesystem.h

@ -139,16 +139,16 @@ typedef struct
#pragma pack( 1 ) #pragma pack( 1 )
typedef struct zip_header_s typedef struct zip_header_s
{ {
uint signature; // little endian ZIP_HEADER uint signature; // little endian ZIP_HEADER
u_int16_t version; // version of pkzip need to unpack u_int16_t version; // version of pkzip need to unpack
u_int16_t flags; // flags (16 bits == 16 flags) u_int16_t flags; // flags (16 bits == 16 flags)
u_int16_t compression_flags; // compression flags (bits) u_int16_t compression_flags; // compression flags (bits)
uint dos_date; // file modification time and file modification date uint dos_date; // file modification time and file modification date
uint crc32; //crc32 uint crc32; //crc32
uint compressed_size; uint compressed_size;
uint uncompressed_size; uint uncompressed_size;
u_int16_t filename_len; u_int16_t filename_len;
u_int16_t extrafield_len; u_int16_t extrafield_len;
} zip_header_t; } zip_header_t;
#pragma pack( ) #pragma pack( )
@ -161,46 +161,46 @@ typedef struct zip_header_s
#pragma pack( 1 ) #pragma pack( 1 )
typedef struct zip_header_extra_s typedef struct zip_header_extra_s
{ {
uint signature; // ZIP_HEADER_SPANNED uint signature; // ZIP_HEADER_SPANNED
uint crc32; uint crc32;
uint compressed_size; uint compressed_size;
uint uncompressed_size; uint uncompressed_size;
} zip_header_extra_t; } zip_header_extra_t;
#pragma pack( ) #pragma pack( )
#pragma pack( 1 ) #pragma pack( 1 )
typedef struct zip_cdf_header_s typedef struct zip_cdf_header_s
{ {
uint signature; uint signature;
u_int16_t version; u_int16_t version;
u_int16_t version_need; u_int16_t version_need;
u_int16_t generalPurposeBitFlag; u_int16_t generalPurposeBitFlag;
u_int16_t flags; u_int16_t flags;
u_int16_t modification_time; u_int16_t modification_time;
u_int16_t modification_date; u_int16_t modification_date;
uint crc32; uint crc32;
uint compressed_size; uint compressed_size;
uint uncompressed_size; uint uncompressed_size;
u_int16_t filename_len; u_int16_t filename_len;
u_int16_t extrafield_len; u_int16_t extrafield_len;
u_int16_t file_commentary_len; u_int16_t file_commentary_len;
u_int16_t disk_start; u_int16_t disk_start;
u_int16_t internal_attr; u_int16_t internal_attr;
uint external_attr; uint external_attr;
uint local_header_offset; uint local_header_offset;
} zip_cdf_header_t; } zip_cdf_header_t;
#pragma pack ( ) #pragma pack ( )
#pragma pack( 1 ) #pragma pack( 1 )
typedef struct zip_header_eocd_s typedef struct zip_header_eocd_s
{ {
u_int16_t disk_number; u_int16_t disk_number;
u_int16_t start_disk_number; u_int16_t start_disk_number;
u_int16_t number_central_directory_record; u_int16_t number_central_directory_record;
u_int16_t total_central_directory_record; u_int16_t total_central_directory_record;
uint size_of_central_directory; uint size_of_central_directory;
uint central_directory_offset; uint central_directory_offset;
u_int16_t commentary_len; u_int16_t commentary_len;
} zip_header_eocd_t; } zip_header_eocd_t;
#pragma pack( ) #pragma pack( )

Loading…
Cancel
Save