2006-04-11 16:33:48 +02:00
/*
* LZMA support routines for PhysicsFS .
*
2008-01-23 05:57:47 +01:00
* Please see the file lzma . txt in the lzma / directory .
2006-04-11 16:33:48 +02:00
*
2008-01-23 05:57:47 +01:00
* This file was written by Dennis Schridde , with some peeking at " 7zMain.c "
2006-04-11 16:33:48 +02:00
* by Igor Pavlov .
*/
2007-03-09 09:17:56 +01:00
# if (defined PHYSFS_SUPPORTS_7Z)
2006-04-11 16:33:48 +02:00
# include <stdlib.h>
# include <string.h>
2008-01-23 05:57:47 +01:00
# include <time.h>
2006-04-11 16:33:48 +02:00
# include "physfs.h"
# define __PHYSICSFS_INTERNAL__
# include "physfs_internal.h"
2008-01-23 05:57:47 +01:00
# include "lzma/C/7zCrc.h"
# include "lzma/C/Archive/7z/7zIn.h"
# include "lzma/C/Archive/7z/7zExtract.h"
2006-09-27 09:05:03 +02:00
2008-01-23 05:57:47 +01:00
/* 7z internal from 7zIn.c */
extern int TestSignatureCandidate ( Byte * testBytes ) ;
2006-09-27 09:05:03 +02:00
2008-01-23 05:57:47 +01:00
# ifdef _LZMA_IN_CB
# define BUFFER_SIZE (1 << 12)
# endif /* _LZMA_IN_CB */
2006-09-27 09:05:03 +02:00
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
/*
* Carries filestream metadata through 7 z
*/
typedef struct _FileInputStream
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
ISzAlloc allocImp ; /* Allocation implementation, used by 7z */
ISzAlloc allocTempImp ; /* Temporary allocation implementation, used by 7z */
ISzInStream inStream ; /* Input stream with read callbacks, used by 7z */
void * file ; /* Filehandle, used by read implementation */
# ifdef _LZMA_IN_CB
Byte buffer [ BUFFER_SIZE ] ; /* Buffer, used by read implementation */
# endif /* _LZMA_IN_CB */
} FileInputStream ;
2006-04-11 16:33:48 +02:00
2006-11-05 11:06:02 +01:00
/*
2008-01-23 05:57:47 +01:00
* In the 7 z format archives are splited into blocks , those are called folders
2006-11-05 11:06:02 +01:00
* Set by LZMA_read ( )
*/
typedef struct _LZMAfolder
{
PHYSFS_uint32 index ; /* Index of folder in archive */
PHYSFS_uint32 references ; /* Number of files using this block */
2008-01-23 05:57:47 +01:00
PHYSFS_uint8 * cache ; /* Cached folder */
size_t size ; /* Size of folder */
2006-11-05 11:06:02 +01:00
} LZMAfolder ;
/*
* Set by LZMA_openArchive ( ) , except folder which gets it ' s values
* in LZMA_read ( )
*/
2006-09-27 09:05:03 +02:00
typedef struct _LZMAarchive
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
struct _LZMAfile * files ; /* Array of files, size == archive->db.Database.NumFiles */
LZMAfolder * folders ; /* Array of folders, size == archive->db.Database.NumFolders */
2006-09-27 09:05:03 +02:00
CArchiveDatabaseEx db ; /* For 7z: Database */
2008-01-23 05:57:47 +01:00
FileInputStream stream ; /* For 7z: Input file incl. read and seek callbacks */
2006-04-11 16:33:48 +02:00
} LZMAarchive ;
2008-01-23 05:57:47 +01:00
/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */
typedef struct _LZMAfile
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
PHYSFS_uint32 index ; /* Index of file in archive */
2006-09-27 09:05:03 +02:00
LZMAarchive * archive ; /* Link to corresponding archive */
2008-01-23 05:57:47 +01:00
LZMAfolder * folder ; /* Link to corresponding folder */
CFileItem * item ; /* For 7z: File info, eg. name, size */
2006-11-05 11:06:02 +01:00
size_t offset ; /* Offset in folder */
2008-01-23 05:57:47 +01:00
size_t position ; /* Current "virtual" position in file */
} LZMAfile ;
2006-04-11 16:33:48 +02:00
2006-09-27 09:05:03 +02:00
/* Memory management implementations to be passed to 7z */
2006-04-11 16:33:48 +02:00
static void * SzAllocPhysicsFS ( size_t size )
{
return ( ( size = = 0 ) ? NULL : allocator . Malloc ( size ) ) ;
} /* SzAllocPhysicsFS */
static void SzFreePhysicsFS ( void * address )
{
if ( address ! = NULL )
allocator . Free ( address ) ;
} /* SzFreePhysicsFS */
2006-09-27 09:05:03 +02:00
/* Filesystem implementations to be passed to 7z */
# ifdef _LZMA_IN_CB
2008-01-23 05:57:47 +01:00
/*
* Read implementation , to be passed to 7 z
* WARNING : If the ISzInStream in ' object ' is not contained in a valid FileInputStream this _will_ break horribly !
*/
2006-09-27 09:05:03 +02:00
SZ_RESULT SzFileReadImp ( void * object , void * * buffer , size_t maxReqSize ,
size_t * processedSize )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
FileInputStream * s = ( FileInputStream * ) ( object - offsetof ( FileInputStream , inStream ) ) ; // HACK!
PHYSFS_sint64 processedSizeLoc = 0 ;
if ( maxReqSize > BUFFER_SIZE )
maxReqSize = BUFFER_SIZE ;
processedSizeLoc = __PHYSFS_platformRead ( s - > file , s - > buffer , 1 , maxReqSize ) ;
* buffer = s - > buffer ;
2007-03-19 08:44:04 +01:00
if ( processedSize ! = NULL )
* processedSize = ( size_t ) processedSizeLoc ;
2008-01-23 05:57:47 +01:00
2006-09-27 09:05:03 +02:00
return SZ_OK ;
} /* SzFileReadImp */
# else
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
/*
* Read implementation , to be passed to 7 z
* WARNING : If the ISzInStream in ' object ' is not contained in a valid FileInputStream this _will_ break horribly !
*/
2006-09-27 09:05:03 +02:00
SZ_RESULT SzFileReadImp ( void * object , void * buffer , size_t size ,
size_t * processedSize )
{
2008-02-02 03:32:48 +01:00
FileInputStream * s = ( FileInputStream * ) ( ( unsigned long ) object - offsetof ( FileInputStream , inStream ) ) ; // HACK!
2008-01-23 05:57:47 +01:00
size_t processedSizeLoc = __PHYSFS_platformRead ( s - > file , buffer , 1 , size ) ;
2006-09-27 09:05:03 +02:00
if ( processedSize ! = 0 )
* processedSize = processedSizeLoc ;
2006-04-11 16:33:48 +02:00
return SZ_OK ;
} /* SzFileReadImp */
2006-09-27 09:05:03 +02:00
# endif
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
/*
* Seek implementation , to be passed to 7 z
* WARNING : If the ISzInStream in ' object ' is not contained in a valid FileInputStream this _will_ break horribly !
*/
2006-04-11 16:33:48 +02:00
SZ_RESULT SzFileSeekImp ( void * object , CFileSize pos )
{
2008-02-02 03:32:48 +01:00
FileInputStream * s = ( FileInputStream * ) ( ( unsigned long ) object - offsetof ( FileInputStream , inStream ) ) ; // HACK!
2008-01-23 05:57:47 +01:00
if ( __PHYSFS_platformSeek ( s - > file , ( PHYSFS_uint64 ) pos ) )
2006-04-11 16:33:48 +02:00
return SZ_OK ;
return SZE_FAIL ;
} /* SzFileSeekImp */
2006-09-27 09:05:03 +02:00
/*
2008-01-23 05:57:47 +01:00
* Translate Microsoft FILETIME ( used by 7 zip ) into UNIX timestamp
2006-09-27 09:05:03 +02:00
*/
2008-01-23 05:57:47 +01:00
static PHYSFS_sint64 lzma_filetime_to_unix_timestamp ( CArchiveFileTime * ft )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
/* MS counts in nanoseconds ... */
const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64 ( 10000000 ) ;
/* MS likes to count seconds since 01.01.1601 ... */
const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64 ( 11644473600 ) ;
PHYSFS_uint64 filetime = ft - > Low | ( ( PHYSFS_uint64 ) ft - > High < < 32 ) ;
return filetime / FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF ;
} /* lzma_filetime_to_unix_timestamp */
/*
* Compare a file with a given name , C89 stdlib variant
* Used for sorting
*/
static int lzma_file_cmp_stdlib ( const void * key , const void * object )
{
const char * name = ( const char * ) key ;
LZMAfile * file = ( LZMAfile * ) object ;
return ( strcmp ( name , file - > item - > Name ) ) ;
} /* lzma_file_cmp_posix */
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
/*
* Compare two files with each other based on the name
* Used for sorting
*/
static int lzma_file_cmp ( void * _a , PHYSFS_uint32 one , PHYSFS_uint32 two )
{
LZMAfile * files = ( LZMAfile * ) _a ;
return ( strcmp ( files [ one ] . item - > Name , files [ two ] . item - > Name ) ) ;
} /* lzma_file_cmp */
/*
* Swap two entries in the file array
*/
static void lzma_file_swap ( void * _a , PHYSFS_uint32 one , PHYSFS_uint32 two )
{
LZMAfile tmp ;
LZMAfile * first = & ( ( ( LZMAfile * ) _a ) [ one ] ) ;
LZMAfile * second = & ( ( ( LZMAfile * ) _a ) [ two ] ) ;
memcpy ( & tmp , first , sizeof ( LZMAfile ) ) ;
memcpy ( first , second , sizeof ( LZMAfile ) ) ;
memcpy ( second , & tmp , sizeof ( LZMAfile ) ) ;
} /* lzma_file_swap */
/*
* Find entry ' name ' in ' archive '
*/
static LZMAfile * lzma_find_file ( LZMAarchive * archive , const char * name )
{
LZMAfile * file = bsearch ( name , archive - > files , archive - > db . Database . NumFiles , sizeof ( * archive - > files ) , lzma_file_cmp_stdlib ) ; // FIXME: Should become __PHYSFS_search!!!
BAIL_IF_MACRO ( file = = NULL , ERR_NO_SUCH_FILE , NULL ) ;
return ( file ) ;
} /* lzma_find_file */
2006-04-11 16:33:48 +02:00
2006-09-27 09:05:03 +02:00
/*
2008-01-23 05:57:47 +01:00
* Load metadata for the file at given index
2006-09-27 09:05:03 +02:00
*/
2008-01-23 05:57:47 +01:00
static int lzma_file_init ( LZMAarchive * archive , PHYSFS_uint32 fileIndex )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
LZMAfile * file = & archive - > files [ fileIndex ] ;
PHYSFS_uint32 folderIndex = archive - > db . FileIndexToFolderIndexMap [ fileIndex ] ;
file - > index = fileIndex ; // Store index into 7z array, since we sort our own.
file - > archive = archive ;
file - > folder = ( folderIndex ! = ( PHYSFS_uint32 ) - 1 ? & archive - > folders [ folderIndex ] : NULL ) ; // Directories don't have a folder (they contain no own data...)
file - > item = & archive - > db . Database . Files [ fileIndex ] ; // Holds crucial data and is often referenced -> Store link
file - > position = 0 ;
file - > offset = 0 ; /* Offset will be set by LZMA_read() */
return ( 1 ) ;
} /* lzma_load_file */
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
/*
* Load metadata for all files
*/
static int lzma_files_init ( LZMAarchive * archive )
{
PHYSFS_uint32 fileIndex = 0 , numFiles = archive - > db . Database . NumFiles ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
for ( fileIndex = 0 ; fileIndex < numFiles ; fileIndex + + )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
if ( ! lzma_file_init ( archive , fileIndex ) )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
return ( 0 ) ; // FALSE on failure
}
} /* for */
__PHYSFS_sort ( archive - > files , numFiles , lzma_file_cmp , lzma_file_swap ) ;
return ( 1 ) ;
} /* lzma_load_files */
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
/*
* Initialise specified archive
*/
static void lzma_archive_init ( LZMAarchive * archive )
{
memset ( archive , 0 , sizeof ( * archive ) ) ;
/* Prepare callbacks for 7z */
archive - > stream . inStream . Read = SzFileReadImp ;
archive - > stream . inStream . Seek = SzFileSeekImp ;
archive - > stream . allocImp . Alloc = SzAllocPhysicsFS ;
archive - > stream . allocImp . Free = SzFreePhysicsFS ;
archive - > stream . allocTempImp . Alloc = SzAllocPhysicsFS ;
archive - > stream . allocTempImp . Free = SzFreePhysicsFS ;
}
/*
* Deinitialise archive
*/
static void lzma_archive_exit ( LZMAarchive * archive )
{
/* Free arrays */
allocator . Free ( archive - > folders ) ;
allocator . Free ( archive - > files ) ;
allocator . Free ( archive ) ;
}
2006-04-11 16:33:48 +02:00
/*
* Wrap all 7 z calls in this , so the physfs error state is set appropriately .
*/
static int lzma_err ( SZ_RESULT rc )
{
switch ( rc )
{
case SZ_OK : /* Same as LZMA_RESULT_OK */
break ;
case SZE_DATA_ERROR : /* Same as LZMA_RESULT_DATA_ERROR */
__PHYSFS_setError ( ERR_DATA_ERROR ) ;
break ;
case SZE_OUTOFMEMORY :
__PHYSFS_setError ( ERR_OUT_OF_MEMORY ) ;
break ;
case SZE_CRC_ERROR :
__PHYSFS_setError ( ERR_CORRUPTED ) ;
break ;
case SZE_NOTIMPL :
__PHYSFS_setError ( ERR_NOT_IMPLEMENTED ) ;
break ;
case SZE_FAIL :
__PHYSFS_setError ( ERR_UNKNOWN_ERROR ) ; /* !!! FIXME: right? */
break ;
case SZE_ARCHIVE_ERROR :
__PHYSFS_setError ( ERR_CORRUPTED ) ; /* !!! FIXME: right? */
break ;
default :
__PHYSFS_setError ( ERR_UNKNOWN_ERROR ) ;
} /* switch */
return ( rc ) ;
} /* lzma_err */
static PHYSFS_sint64 LZMA_read ( fvoid * opaque , void * outBuffer ,
PHYSFS_uint32 objSize , PHYSFS_uint32 objCount )
{
2008-01-23 05:57:47 +01:00
LZMAfile * file = ( LZMAfile * ) opaque ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
size_t wantedSize = objSize * objCount ;
size_t remainingSize = file - > item - > Size - file - > position ;
size_t fileSize = 0 ;
2007-03-12 04:41:20 +01:00
2006-09-27 09:05:03 +02:00
BAIL_IF_MACRO ( wantedSize = = 0 , NULL , 0 ) ; /* quick rejection. */
BAIL_IF_MACRO ( remainingSize = = 0 , ERR_PAST_EOF , 0 ) ;
2006-04-11 16:33:48 +02:00
2006-09-27 09:05:03 +02:00
if ( remainingSize < wantedSize )
2006-04-11 16:33:48 +02:00
{
2006-09-27 09:05:03 +02:00
wantedSize = remainingSize - ( remainingSize % objSize ) ;
objCount = ( PHYSFS_uint32 ) ( remainingSize / objSize ) ;
2006-04-11 16:33:48 +02:00
BAIL_IF_MACRO ( objCount = = 0 , ERR_PAST_EOF , 0 ) ; /* quick rejection. */
2006-09-27 09:05:03 +02:00
__PHYSFS_setError ( ERR_PAST_EOF ) ; /* this is always true here. */
2006-04-11 16:33:48 +02:00
} /* if */
2006-11-05 11:06:02 +01:00
/* Only decompress the folder if it is not allready cached */
2008-01-23 05:57:47 +01:00
if ( file - > folder - > cache = = NULL )
2007-03-10 07:26:11 +01:00
{
int rc = lzma_err ( SzExtract (
2008-01-23 05:57:47 +01:00
& file - > archive - > stream . inStream , /* compressed data */
& file - > archive - > db , /* 7z's database, containing everything */
file - > index , /* Index into database arrays */
2006-11-05 11:06:02 +01:00
/* Index of cached folder, will be changed by SzExtract */
2008-01-23 05:57:47 +01:00
& file - > folder - > index ,
2006-11-05 11:06:02 +01:00
/* Cache for decompressed folder, allocated/freed by SzExtract */
2008-01-23 05:57:47 +01:00
& file - > folder - > cache ,
2006-11-05 11:06:02 +01:00
/* Size of cache, will be changed by SzExtract */
2008-01-23 05:57:47 +01:00
& file - > folder - > size ,
2006-11-05 11:06:02 +01:00
/* Offset of this file inside the cache, set by SzExtract */
2008-01-23 05:57:47 +01:00
& file - > offset ,
2006-11-05 11:06:02 +01:00
& fileSize , /* Size of this file */
2008-01-23 05:57:47 +01:00
& file - > archive - > stream . allocImp ,
& file - > archive - > stream . allocTempImp ) ) ;
2007-03-10 07:26:11 +01:00
if ( rc ! = SZ_OK )
2006-11-05 11:06:02 +01:00
return - 1 ;
2007-03-10 07:26:11 +01:00
} /* if */
2006-09-27 09:05:03 +02:00
/* Copy wanted bytes over from cache to outBuffer */
2008-01-23 05:57:47 +01:00
memcpy ( outBuffer ,
( file - > folder - > cache +
file - > offset + file - > position ) ,
wantedSize ) ;
file - > position + = wantedSize ; /* Increase virtual position */
2006-09-27 09:05:03 +02:00
return objCount ;
2006-04-11 16:33:48 +02:00
} /* LZMA_read */
static PHYSFS_sint64 LZMA_write ( fvoid * opaque , const void * buf ,
PHYSFS_uint32 objSize , PHYSFS_uint32 objCount )
{
BAIL_MACRO ( ERR_NOT_SUPPORTED , - 1 ) ;
} /* LZMA_write */
static int LZMA_eof ( fvoid * opaque )
{
2008-01-23 05:57:47 +01:00
LZMAfile * file = ( LZMAfile * ) opaque ;
return ( file - > position > = file - > item - > Size ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_eof */
static PHYSFS_sint64 LZMA_tell ( fvoid * opaque )
{
2008-01-23 05:57:47 +01:00
LZMAfile * file = ( LZMAfile * ) opaque ;
return ( file - > position ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_tell */
static int LZMA_seek ( fvoid * opaque , PHYSFS_uint64 offset )
{
2008-01-23 05:57:47 +01:00
LZMAfile * file = ( LZMAfile * ) opaque ;
2006-04-11 16:33:48 +02:00
BAIL_IF_MACRO ( offset < 0 , ERR_SEEK_OUT_OF_RANGE , 0 ) ;
2008-01-23 05:57:47 +01:00
BAIL_IF_MACRO ( offset > file - > item - > Size , ERR_PAST_EOF , 0 ) ;
file - > position = offset ; /* We only use a virtual position... */
2006-04-11 16:33:48 +02:00
2006-09-27 09:05:03 +02:00
return 1 ;
2006-04-11 16:33:48 +02:00
} /* LZMA_seek */
static PHYSFS_sint64 LZMA_fileLength ( fvoid * opaque )
{
2008-01-23 05:57:47 +01:00
LZMAfile * file = ( LZMAfile * ) opaque ;
return ( file - > item - > Size ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_fileLength */
static int LZMA_fileClose ( fvoid * opaque )
{
2008-01-23 05:57:47 +01:00
LZMAfile * file = ( LZMAfile * ) opaque ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
BAIL_IF_MACRO ( file - > folder = = NULL , ERR_NOT_A_FILE , 0 ) ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
/* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
if ( file - > folder - > references > 0 )
file - > folder - > references - - ;
if ( file - > folder - > references = = 0 )
2006-11-05 11:06:02 +01:00
{
2008-01-23 05:57:47 +01:00
/* Free the cache which might have been allocated by LZMA_read() */
allocator . Free ( file - > folder - > cache ) ;
file - > folder - > cache = NULL ;
2006-11-05 11:06:02 +01:00
}
2006-04-11 16:33:48 +02:00
return ( 1 ) ;
} /* LZMA_fileClose */
static int LZMA_isArchive ( const char * filename , int forWriting )
{
PHYSFS_uint8 sig [ k7zSignatureSize ] ;
void * in ;
BAIL_IF_MACRO ( forWriting , ERR_ARC_IS_READ_ONLY , 0 ) ;
in = __PHYSFS_platformOpenRead ( filename ) ;
BAIL_IF_MACRO ( in = = NULL , NULL , 0 ) ;
2008-01-23 05:57:47 +01:00
/* Read signature bytes */
2006-04-11 16:33:48 +02:00
if ( __PHYSFS_platformRead ( in , sig , k7zSignatureSize , 1 ) ! = 1 )
2008-01-23 05:57:47 +01:00
{
__PHYSFS_platformClose ( in ) ; // Don't forget to close the file before returning...
2006-04-11 16:33:48 +02:00
BAIL_MACRO ( NULL , 0 ) ;
2008-01-23 05:57:47 +01:00
}
2006-09-27 09:05:03 +02:00
2006-04-11 16:33:48 +02:00
__PHYSFS_platformClose ( in ) ;
2008-01-23 05:57:47 +01:00
/* Test whether sig is the 7z signature */
return ( TestSignatureCandidate ( sig ) ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_isArchive */
static void * LZMA_openArchive ( const char * name , int forWriting )
{
2008-01-23 05:57:47 +01:00
size_t len = 0 ;
2006-09-27 11:21:56 +02:00
LZMAarchive * archive = NULL ;
2006-04-11 16:33:48 +02:00
BAIL_IF_MACRO ( forWriting , ERR_ARC_IS_READ_ONLY , NULL ) ;
2006-11-05 11:06:02 +01:00
BAIL_IF_MACRO ( ! LZMA_isArchive ( name , forWriting ) , ERR_UNSUPPORTED_ARCHIVE , 0 ) ;
2006-09-27 09:05:03 +02:00
archive = ( LZMAarchive * ) allocator . Malloc ( sizeof ( LZMAarchive ) ) ;
BAIL_IF_MACRO ( archive = = NULL , ERR_OUT_OF_MEMORY , NULL ) ;
2008-01-23 05:57:47 +01:00
lzma_archive_init ( archive ) ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
if ( ( archive - > stream . file = __PHYSFS_platformOpenRead ( name ) ) = = NULL )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
__PHYSFS_platformClose ( archive - > stream . file ) ;
lzma_archive_exit ( archive ) ;
return ( NULL ) ; // Error is set by platformOpenRead!
}
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
CrcGenerateTable ( ) ;
2006-04-11 16:33:48 +02:00
SzArDbExInit ( & archive - > db ) ;
2008-01-23 05:57:47 +01:00
if ( lzma_err ( SzArchiveOpen ( & archive - > stream . inStream ,
& archive - > db ,
& archive - > stream . allocImp ,
& archive - > stream . allocTempImp ) ) ! = SZ_OK )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
SzArDbExFree ( & archive - > db , SzFreePhysicsFS ) ;
__PHYSFS_platformClose ( archive - > stream . file ) ;
lzma_archive_exit ( archive ) ;
return NULL ; // Error is set by lzma_err!
2006-04-11 16:33:48 +02:00
} /* if */
2008-01-23 05:57:47 +01:00
len = archive - > db . Database . NumFiles * sizeof ( LZMAfile ) ;
archive - > files = ( LZMAfile * ) allocator . Malloc ( len ) ;
if ( archive - > files = = NULL )
{
SzArDbExFree ( & archive - > db , SzFreePhysicsFS ) ;
__PHYSFS_platformClose ( archive - > stream . file ) ;
lzma_archive_exit ( archive ) ;
BAIL_MACRO ( ERR_OUT_OF_MEMORY , NULL ) ;
}
/*
* Init with 0 so we know when a folder is already cached
* Values will be set by LZMA_openRead ( )
*/
memset ( archive - > files , 0 , len ) ;
2006-11-05 11:06:02 +01:00
len = archive - > db . Database . NumFolders * sizeof ( LZMAfolder ) ;
2008-01-23 05:57:47 +01:00
archive - > folders = ( LZMAfolder * ) allocator . Malloc ( len ) ;
if ( archive - > folders = = NULL )
{
SzArDbExFree ( & archive - > db , SzFreePhysicsFS ) ;
__PHYSFS_platformClose ( archive - > stream . file ) ;
lzma_archive_exit ( archive ) ;
BAIL_MACRO ( ERR_OUT_OF_MEMORY , NULL ) ;
}
2006-11-05 11:06:02 +01:00
/*
* Init with 0 so we know when a folder is already cached
* Values will be set by LZMA_read ( )
*/
2008-01-23 05:57:47 +01:00
memset ( archive - > folders , 0 , len ) ;
if ( ! lzma_files_init ( archive ) )
{
SzArDbExFree ( & archive - > db , SzFreePhysicsFS ) ;
__PHYSFS_platformClose ( archive - > stream . file ) ;
lzma_archive_exit ( archive ) ;
BAIL_MACRO ( ERR_UNKNOWN_ERROR , NULL ) ;
}
2006-11-05 11:06:02 +01:00
2006-04-11 16:33:48 +02:00
return ( archive ) ;
} /* LZMA_openArchive */
/*
* Moved to seperate function so we can use alloca then immediately throw
* away the allocated stack space . . .
*/
static void doEnumCallback ( PHYSFS_EnumFilesCallback cb , void * callbackdata ,
2008-01-23 05:57:47 +01:00
const char * odir , const char * str , size_t flen )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
char * newstr = __PHYSFS_smallAlloc ( flen + 1 ) ;
2006-04-11 16:33:48 +02:00
if ( newstr = = NULL )
return ;
2008-01-23 05:57:47 +01:00
memcpy ( newstr , str , flen ) ;
newstr [ flen ] = ' \0 ' ;
2006-04-11 16:33:48 +02:00
cb ( callbackdata , odir , newstr ) ;
2007-03-24 04:54:58 +01:00
__PHYSFS_smallFree ( newstr ) ;
2006-04-11 16:33:48 +02:00
} /* doEnumCallback */
static void LZMA_enumerateFiles ( dvoid * opaque , const char * dname ,
int omitSymLinks , PHYSFS_EnumFilesCallback cb ,
const char * origdir , void * callbackdata )
{
2008-01-23 05:57:47 +01:00
size_t dlen = strlen ( dname ) ,
dlen_inc = dlen + ( ( dlen > 0 ) ? 1 : 0 ) ;
2006-04-11 16:33:48 +02:00
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
2008-02-02 03:32:48 +01:00
LZMAfile * file = NULL ,
* lastFile = & archive - > files [ archive - > db . Database . NumFiles ] ;
if ( dlen )
{
file = lzma_find_file ( archive , dname ) ;
if ( file ! = NULL ) // if 'file' is NULL it should stay so, otherwise errors will not be handled
file + = 1 ;
}
else
{
file = archive - > files ;
}
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
BAIL_IF_MACRO ( file = = NULL , ERR_NO_SUCH_FILE , ) ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
while ( file < lastFile )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
const char * fname = file - > item - > Name ;
const char * dirNameEnd = fname + dlen_inc ;
if ( strncmp ( dname , fname , dlen ) ! = 0 ) /* Stop after mismatch, archive->files is sorted */
break ;
if ( strchr ( dirNameEnd , ' / ' ) ) /* Skip subdirs */
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
file + + ;
continue ;
}
/* Do the actual callback... */
doEnumCallback ( cb , callbackdata , origdir , dirNameEnd , strlen ( dirNameEnd ) ) ;
file + + ;
}
2006-04-11 16:33:48 +02:00
} /* LZMA_enumerateFiles */
static int LZMA_exists ( dvoid * opaque , const char * name )
{
2006-09-27 09:05:03 +02:00
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
2008-01-23 05:57:47 +01:00
return ( lzma_find_file ( archive , name ) ! = NULL ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_exists */
static PHYSFS_sint64 LZMA_getLastModTime ( dvoid * opaque ,
2006-09-27 09:05:03 +02:00
const char * name ,
int * fileExists )
2006-04-11 16:33:48 +02:00
{
2008-01-23 05:57:47 +01:00
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
LZMAfile * file = lzma_find_file ( archive , name ) ;
* fileExists = ( file ! = NULL ) ;
BAIL_IF_MACRO ( file = = NULL , NULL , - 1 ) ;
BAIL_IF_MACRO ( ! file - > item - > IsLastWriteTimeDefined , NULL , - 1 ) ; // write-time may not be defined for every file
return ( lzma_filetime_to_unix_timestamp ( & file - > item - > LastWriteTime ) ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_getLastModTime */
static int LZMA_isDirectory ( dvoid * opaque , const char * name , int * fileExists )
{
2006-09-27 09:05:03 +02:00
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
2008-01-23 05:57:47 +01:00
LZMAfile * file = lzma_find_file ( archive , name ) ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
* fileExists = ( file ! = NULL ) ;
2006-04-11 16:33:48 +02:00
2008-02-02 03:32:48 +01:00
return ( file = = NULL ? 0 : file - > item - > IsDirectory ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_isDirectory */
static int LZMA_isSymLink ( dvoid * opaque , const char * name , int * fileExists )
{
BAIL_MACRO ( ERR_NOT_SUPPORTED , 0 ) ;
} /* LZMA_isSymLink */
static fvoid * LZMA_openRead ( dvoid * opaque , const char * name , int * fileExists )
{
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
2008-01-23 05:57:47 +01:00
LZMAfile * file = lzma_find_file ( archive , name ) ;
2006-09-27 09:05:03 +02:00
2008-01-23 05:57:47 +01:00
* fileExists = ( file ! = NULL ) ;
BAIL_IF_MACRO ( file = = NULL , ERR_NO_SUCH_FILE , NULL ) ;
BAIL_IF_MACRO ( file - > folder = = NULL , ERR_NOT_A_FILE , NULL ) ;
2006-04-11 16:33:48 +02:00
2008-01-23 05:57:47 +01:00
file - > folder - > references + + ; // Increase refcount for automatic cleanup...
2006-11-05 11:06:02 +01:00
2008-01-23 05:57:47 +01:00
return ( file ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_openRead */
static fvoid * LZMA_openWrite ( dvoid * opaque , const char * filename )
{
BAIL_MACRO ( ERR_NOT_SUPPORTED , NULL ) ;
} /* LZMA_openWrite */
static fvoid * LZMA_openAppend ( dvoid * opaque , const char * filename )
{
BAIL_MACRO ( ERR_NOT_SUPPORTED , NULL ) ;
} /* LZMA_openAppend */
static void LZMA_dirClose ( dvoid * opaque )
{
2006-09-27 09:05:03 +02:00
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
2008-01-23 05:57:47 +01:00
PHYSFS_uint32 fileIndex = 0 , numFiles = archive - > db . Database . NumFiles ;
2006-09-27 09:05:03 +02:00
2008-01-23 05:57:47 +01:00
for ( fileIndex = 0 ; fileIndex < numFiles ; fileIndex + + )
2006-09-27 09:05:03 +02:00
{
2008-01-23 05:57:47 +01:00
LZMA_fileClose ( & archive - > files [ fileIndex ] ) ;
} /* for */
2006-04-11 16:33:48 +02:00
2006-09-27 09:05:03 +02:00
SzArDbExFree ( & archive - > db , SzFreePhysicsFS ) ;
2008-01-23 05:57:47 +01:00
__PHYSFS_platformClose ( archive - > stream . file ) ;
lzma_archive_exit ( archive ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_dirClose */
static int LZMA_remove ( dvoid * opaque , const char * name )
{
BAIL_MACRO ( ERR_NOT_SUPPORTED , 0 ) ;
} /* LZMA_remove */
static int LZMA_mkdir ( dvoid * opaque , const char * name )
{
BAIL_MACRO ( ERR_NOT_SUPPORTED , 0 ) ;
} /* LZMA_mkdir */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_LZMA =
{
" 7Z " ,
LZMA_ARCHIVE_DESCRIPTION ,
" Dennis Schridde <devurandom@gmx.net> " ,
" http://icculus.org/physfs/ " ,
} ;
const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
{
& __PHYSFS_ArchiveInfo_LZMA ,
LZMA_isArchive , /* isArchive() method */
LZMA_openArchive , /* openArchive() method */
LZMA_enumerateFiles , /* enumerateFiles() method */
LZMA_exists , /* exists() method */
LZMA_isDirectory , /* isDirectory() method */
LZMA_isSymLink , /* isSymLink() method */
LZMA_getLastModTime , /* getLastModTime() method */
LZMA_openRead , /* openRead() method */
LZMA_openWrite , /* openWrite() method */
LZMA_openAppend , /* openAppend() method */
LZMA_remove , /* remove() method */
LZMA_mkdir , /* mkdir() method */
LZMA_dirClose , /* dirClose() method */
LZMA_read , /* read() method */
LZMA_write , /* write() method */
LZMA_eof , /* eof() method */
LZMA_tell , /* tell() method */
LZMA_seek , /* seek() method */
LZMA_fileLength , /* fileLength() method */
LZMA_fileClose /* fileClose() method */
} ;
2007-03-09 09:17:56 +01:00
# endif /* defined PHYSFS_SUPPORTS_7Z */
2006-04-11 16:33:48 +02:00
/* end of lzma.c ... */