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 .
*/
# define __PHYSICSFS_INTERNAL__
# include "physfs_internal.h"
2012-03-23 05:52:32 +01:00
# if PHYSFS_SUPPORTS_7Z
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 */
2010-08-30 09:01:57 +02:00
PHYSFS_Io * io ; /* Filehandle, used by read implementation */
2008-01-23 05:57:47 +01:00
# 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
{
2010-01-28 08:35:32 +01:00
FileInputStream * s = ( FileInputStream * ) ( object - offsetof ( FileInputStream , inStream ) ) ; /* HACK! */
2008-01-23 05:57:47 +01:00
PHYSFS_sint64 processedSizeLoc = 0 ;
if ( maxReqSize > BUFFER_SIZE )
maxReqSize = BUFFER_SIZE ;
2010-08-30 09:01:57 +02:00
processedSizeLoc = s - > io - > read ( s - > io , s - > buffer , maxReqSize ) ;
2008-01-23 05:57:47 +01:00
* 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 )
{
2010-01-28 08:35:32 +01:00
FileInputStream * s = ( FileInputStream * ) ( ( unsigned long ) object - offsetof ( FileInputStream , inStream ) ) ; /* HACK! */
2010-08-30 09:01:57 +02:00
const size_t processedSizeLoc = s - > io - > read ( s - > io , buffer , size ) ;
if ( processedSize ! = NULL )
2006-09-27 09:05:03 +02:00
* 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 )
{
2010-01-28 08:35:32 +01:00
FileInputStream * s = ( FileInputStream * ) ( ( unsigned long ) object - offsetof ( FileInputStream , inStream ) ) ; /* HACK! */
2010-08-30 09:01:57 +02:00
if ( s - > io - > seek ( s - > io , ( 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 ;
2010-01-28 08:27:45 +01:00
return strcmp ( name , file - > item - > Name ) ;
2008-01-23 05:57:47 +01:00
} /* 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 ;
2010-01-28 08:27:45 +01:00
return strcmp ( files [ one ] . item - > Name , files [ two ] . item - > Name ) ;
2008-01-23 05:57:47 +01:00
} /* 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 '
*/
2010-02-15 20:02:36 +01:00
static LZMAfile * lzma_find_file ( const LZMAarchive * archive , const char * name )
2008-01-23 05:57:47 +01:00
{
2010-01-28 08:35:32 +01:00
LZMAfile * file = bsearch ( name , archive - > files , archive - > db . Database . NumFiles , sizeof ( * archive - > files ) , lzma_file_cmp_stdlib ) ; /* FIXME: Should become __PHYSFS_search!!! */
2008-01-23 05:57:47 +01:00
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( file = = NULL , PHYSFS_ERR_NO_SUCH_PATH , NULL ) ;
2008-01-23 05:57:47 +01:00
2010-01-28 08:27:45 +01:00
return file ;
2008-01-23 05:57:47 +01:00
} /* 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 ] ;
2010-01-28 08:35:32 +01:00
file - > index = fileIndex ; /* Store index into 7z array, since we sort our own. */
2008-01-23 05:57:47 +01:00
file - > archive = archive ;
2010-01-28 08:35:32 +01:00
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 */
2008-01-23 05:57:47 +01:00
file - > position = 0 ;
file - > offset = 0 ; /* Offset will be set by LZMA_read() */
2010-01-28 08:27:45 +01:00
return 1 ;
2008-01-23 05:57:47 +01:00
} /* 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
{
2010-01-28 08:35:32 +01:00
return 0 ; /* FALSE on failure */
2008-01-23 05:57:47 +01:00
}
} /* for */
__PHYSFS_sort ( archive - > files , numFiles , lzma_file_cmp , lzma_file_swap ) ;
2010-01-28 08:27:45 +01:00
return 1 ;
2008-01-23 05:57:47 +01:00
} /* 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 */
2012-03-20 20:38:12 +01:00
__PHYSFS_setError ( PHYSFS_ERR_CORRUPT ) ; /*!!!FIXME: was "PHYSFS_ERR_DATA_ERROR" */
2006-04-11 16:33:48 +02:00
break ;
case SZE_OUTOFMEMORY :
2012-03-20 20:38:12 +01:00
__PHYSFS_setError ( PHYSFS_ERR_OUT_OF_MEMORY ) ;
2006-04-11 16:33:48 +02:00
break ;
case SZE_CRC_ERROR :
2012-03-20 20:38:12 +01:00
__PHYSFS_setError ( PHYSFS_ERR_CORRUPT ) ;
2006-04-11 16:33:48 +02:00
break ;
case SZE_NOTIMPL :
2012-03-20 20:38:12 +01:00
__PHYSFS_setError ( PHYSFS_ERR_UNSUPPORTED ) ;
2006-04-11 16:33:48 +02:00
break ;
case SZE_FAIL :
2012-03-20 20:38:12 +01:00
__PHYSFS_setError ( PHYSFS_ERR_OTHER_ERROR ) ; /* !!! FIXME: right? */
2006-04-11 16:33:48 +02:00
break ;
case SZE_ARCHIVE_ERROR :
2012-03-20 20:38:12 +01:00
__PHYSFS_setError ( PHYSFS_ERR_CORRUPT ) ; /* !!! FIXME: right? */
2006-04-11 16:33:48 +02:00
break ;
default :
2012-03-20 20:38:12 +01:00
__PHYSFS_setError ( PHYSFS_ERR_OTHER_ERROR ) ;
2006-04-11 16:33:48 +02:00
} /* switch */
2010-01-28 08:27:45 +01:00
return rc ;
2006-04-11 16:33:48 +02:00
} /* lzma_err */
2010-08-30 09:01:57 +02:00
static PHYSFS_sint64 LZMA_read ( PHYSFS_Io * io , void * outBuf , PHYSFS_uint64 len )
2006-04-11 16:33:48 +02:00
{
2010-08-30 09:01:57 +02:00
LZMAfile * file = ( LZMAfile * ) io - > opaque ;
2006-04-11 16:33:48 +02:00
2010-08-21 08:47:58 +02:00
size_t wantedSize = ( size_t ) len ;
2010-08-30 09:01:57 +02:00
const size_t remainingSize = file - > item - > Size - file - > position ;
2008-01-23 05:57:47 +01:00
size_t fileSize = 0 ;
2007-03-12 04:41:20 +01:00
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( wantedSize = = 0 , ERRPASS , 0 ) ; /* quick rejection. */
BAIL_IF_MACRO ( remainingSize = = 0 , PHYSFS_ERR_PAST_EOF , 0 ) ;
2006-04-11 16:33:48 +02:00
2010-08-21 08:47:58 +02:00
if ( wantedSize > remainingSize )
wantedSize = remainingSize ;
2006-04-11 16:33:48 +02:00
2010-08-30 09:01:57 +02:00
/* Only decompress the folder if it is not already cached */
2008-01-23 05:57:47 +01:00
if ( file - > folder - > cache = = NULL )
2007-03-10 07:26:11 +01:00
{
2010-08-30 09:01:57 +02:00
const 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
2010-08-21 08:47:58 +02:00
/* Copy wanted bytes over from cache to outBuf */
2010-08-30 09:01:57 +02:00
memcpy ( outBuf , ( file - > folder - > cache + file - > offset + file - > position ) ,
2008-01-23 05:57:47 +01:00
wantedSize ) ;
file - > position + = wantedSize ; /* Increase virtual position */
2010-08-21 08:47:58 +02:00
return wantedSize ;
2006-04-11 16:33:48 +02:00
} /* LZMA_read */
2010-08-30 09:01:57 +02:00
static PHYSFS_sint64 LZMA_write ( PHYSFS_Io * io , const void * b , PHYSFS_uint64 len )
2006-04-11 16:33:48 +02:00
{
2012-03-22 05:05:10 +01:00
BAIL_MACRO ( PHYSFS_ERR_READ_ONLY , - 1 ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_write */
2010-08-30 09:01:57 +02:00
static PHYSFS_sint64 LZMA_tell ( PHYSFS_Io * io )
2006-04-11 16:33:48 +02:00
{
2010-08-30 09:01:57 +02:00
LZMAfile * file = ( LZMAfile * ) io - > opaque ;
return file - > position ;
2006-04-11 16:33:48 +02:00
} /* LZMA_tell */
2010-08-30 09:01:57 +02:00
static int LZMA_seek ( PHYSFS_Io * io , PHYSFS_uint64 offset )
2006-04-11 16:33:48 +02:00
{
2010-08-30 09:01:57 +02:00
LZMAfile * file = ( LZMAfile * ) io - > opaque ;
2006-04-11 16:33:48 +02:00
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( offset > file - > item - > Size , PHYSFS_ERR_PAST_EOF , 0 ) ;
2008-01-23 05:57:47 +01:00
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 */
2010-08-30 09:01:57 +02:00
static PHYSFS_sint64 LZMA_length ( PHYSFS_Io * io )
2006-04-11 16:33:48 +02:00
{
2010-08-30 09:01:57 +02:00
const LZMAfile * file = ( LZMAfile * ) io - > opaque ;
2008-01-23 05:57:47 +01:00
return ( file - > item - > Size ) ;
2010-08-30 09:01:57 +02:00
} /* LZMA_length */
2006-04-11 16:33:48 +02:00
2010-08-30 09:01:57 +02:00
static PHYSFS_Io * LZMA_duplicate ( PHYSFS_Io * _io )
2006-04-11 16:33:48 +02:00
{
2010-08-30 09:01:57 +02:00
/* !!! FIXME: this archiver needs to be reworked to allow multiple
* ! ! ! FIXME : opens before we worry about duplication . */
2012-03-20 20:38:12 +01:00
BAIL_MACRO ( PHYSFS_ERR_UNSUPPORTED , NULL ) ;
2010-08-30 09:01:57 +02:00
} /* LZMA_duplicate */
2006-04-11 16:33:48 +02:00
2006-11-05 11:06:02 +01:00
2010-08-30 09:01:57 +02:00
static int LZMA_flush ( PHYSFS_Io * io ) { return 1 ; /* no write support. */ }
2006-04-11 16:33:48 +02:00
2010-08-30 09:01:57 +02:00
static void LZMA_destroy ( PHYSFS_Io * io )
2006-04-11 16:33:48 +02:00
{
2010-08-30 09:01:57 +02:00
LZMAfile * file = ( LZMAfile * ) io - > opaque ;
2006-04-11 16:33:48 +02:00
2010-08-30 09:01:57 +02:00
if ( file - > folder ! = NULL )
2008-01-23 05:57:47 +01:00
{
2010-08-30 09:01:57 +02: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 )
{
/* Free the cache which might have been allocated by LZMA_read() */
allocator . Free ( file - > folder - > cache ) ;
file - > folder - > cache = NULL ;
}
/* !!! FIXME: we don't free (file) or (file->folder)?! */
} /* if */
} /* LZMA_destroy */
2006-09-27 09:05:03 +02:00
2006-04-11 16:33:48 +02:00
2010-08-30 09:01:57 +02:00
static const PHYSFS_Io LZMA_Io =
{
LZMA_read ,
LZMA_write ,
LZMA_seek ,
LZMA_tell ,
LZMA_length ,
LZMA_duplicate ,
LZMA_flush ,
LZMA_destroy ,
NULL
} ;
2006-04-11 16:33:48 +02:00
2010-08-30 09:01:57 +02:00
static void * LZMA_openArchive ( PHYSFS_Io * io , const char * name , int forWriting )
2006-04-11 16:33:48 +02:00
{
2010-08-30 09:01:57 +02:00
PHYSFS_uint8 sig [ k7zSignatureSize ] ;
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
2010-08-30 09:01:57 +02:00
assert ( io ! = NULL ) ; /* shouldn't ever happen. */
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( forWriting , PHYSFS_ERR_READ_ONLY , NULL ) ;
2010-08-30 09:01:57 +02:00
if ( io - > read ( io , sig , k7zSignatureSize ) ! = k7zSignatureSize )
2012-03-20 20:38:12 +01:00
return 0 ;
BAIL_IF_MACRO ( ! TestSignatureCandidate ( sig ) , PHYSFS_ERR_UNSUPPORTED , NULL ) ;
BAIL_IF_MACRO ( ! io - > seek ( io , 0 ) , ERRPASS , NULL ) ;
2006-09-27 09:05:03 +02:00
archive = ( LZMAarchive * ) allocator . Malloc ( sizeof ( LZMAarchive ) ) ;
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( archive = = NULL , PHYSFS_ERR_OUT_OF_MEMORY , NULL ) ;
2006-09-27 09:05:03 +02:00
2008-01-23 05:57:47 +01:00
lzma_archive_init ( archive ) ;
2010-08-30 09:01:57 +02:00
archive - > stream . io = io ;
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 ) ;
lzma_archive_exit ( archive ) ;
2010-01-28 08:35:32 +01:00
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 ) ;
lzma_archive_exit ( archive ) ;
2012-03-20 20:38:12 +01:00
BAIL_MACRO ( PHYSFS_ERR_OUT_OF_MEMORY , NULL ) ;
2008-01-23 05:57:47 +01:00
}
/*
* 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 ) ;
lzma_archive_exit ( archive ) ;
2012-03-20 20:38:12 +01:00
BAIL_MACRO ( PHYSFS_ERR_OUT_OF_MEMORY , NULL ) ;
2008-01-23 05:57:47 +01:00
}
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 ) ;
lzma_archive_exit ( archive ) ;
2012-03-20 20:38:12 +01:00
BAIL_MACRO ( PHYSFS_ERR_OTHER_ERROR , NULL ) ;
2008-01-23 05:57:47 +01:00
}
2006-11-05 11:06:02 +01:00
2010-01-28 08:27:45 +01:00
return archive ;
2006-04-11 16:33:48 +02:00
} /* 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 */
2012-03-25 20:52:24 +02:00
static void LZMA_enumerateFiles ( PHYSFS_Dir * opaque , const char * dname ,
2006-04-11 16:33:48 +02:00
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 ) ;
2010-01-28 08:35:32 +01:00
if ( file ! = NULL ) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
2008-02-02 03:32:48 +01:00
file + = 1 ;
}
else
{
file = archive - > files ;
}
2006-04-11 16:33:48 +02:00
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( file = = NULL , PHYSFS_ERR_NO_SUCH_PATH , ) ;
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 */
2012-03-25 20:52:24 +02:00
static PHYSFS_Io * LZMA_openRead ( PHYSFS_Dir * opaque , const char * name ,
int * fileExists )
2006-04-11 16:33:48 +02:00
{
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
2008-01-23 05:57:47 +01:00
LZMAfile * file = lzma_find_file ( archive , name ) ;
2010-08-30 09:01:57 +02:00
PHYSFS_Io * io = NULL ;
2006-09-27 09:05:03 +02:00
2008-01-23 05:57:47 +01:00
* fileExists = ( file ! = NULL ) ;
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( file = = NULL , PHYSFS_ERR_NO_SUCH_PATH , NULL ) ;
BAIL_IF_MACRO ( file - > folder = = NULL , PHYSFS_ERR_NOT_A_FILE , NULL ) ;
2006-04-11 16:33:48 +02:00
2009-06-21 23:37:47 +02:00
file - > position = 0 ;
2010-01-28 08:35:32 +01:00
file - > folder - > references + + ; /* Increase refcount for automatic cleanup... */
2006-11-05 11:06:02 +01:00
2010-08-30 09:01:57 +02:00
io = ( PHYSFS_Io * ) allocator . Malloc ( sizeof ( PHYSFS_Io ) ) ;
2012-03-20 20:38:12 +01:00
BAIL_IF_MACRO ( io = = NULL , PHYSFS_ERR_OUT_OF_MEMORY , NULL ) ;
2010-08-30 09:01:57 +02:00
memcpy ( io , & LZMA_Io , sizeof ( * io ) ) ;
io - > opaque = file ;
return io ;
2006-04-11 16:33:48 +02:00
} /* LZMA_openRead */
2012-03-25 20:52:24 +02:00
static PHYSFS_Io * LZMA_openWrite ( PHYSFS_Dir * opaque , const char * filename )
2006-04-11 16:33:48 +02:00
{
2012-03-22 05:05:10 +01:00
BAIL_MACRO ( PHYSFS_ERR_READ_ONLY , NULL ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_openWrite */
2012-03-25 20:52:24 +02:00
static PHYSFS_Io * LZMA_openAppend ( PHYSFS_Dir * opaque , const char * filename )
2006-04-11 16:33:48 +02:00
{
2012-03-22 05:05:10 +01:00
BAIL_MACRO ( PHYSFS_ERR_READ_ONLY , NULL ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_openAppend */
2012-03-25 20:52:24 +02:00
static void LZMA_closeArchive ( PHYSFS_Dir * opaque )
2006-04-11 16:33:48 +02:00
{
2006-09-27 09:05:03 +02:00
LZMAarchive * archive = ( LZMAarchive * ) opaque ;
2010-08-30 09:01:57 +02:00
#if 0 /* !!! FIXME: you shouldn't have to do this. */
PHYSFS_uint32 fileIndex = 0 , numFiles = archive - > db . Database . NumFiles ;
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 */
2010-08-30 09:01:57 +02:00
# endif
2006-04-11 16:33:48 +02:00
2006-09-27 09:05:03 +02:00
SzArDbExFree ( & archive - > db , SzFreePhysicsFS ) ;
2010-08-30 09:01:57 +02:00
archive - > stream . io - > destroy ( archive - > stream . io ) ;
2008-01-23 05:57:47 +01:00
lzma_archive_exit ( archive ) ;
2012-03-24 15:36:11 +01:00
} /* LZMA_closeArchive */
2006-04-11 16:33:48 +02:00
2012-03-25 20:52:24 +02:00
static int LZMA_remove ( PHYSFS_Dir * opaque , const char * name )
2006-04-11 16:33:48 +02:00
{
2012-03-22 05:05:10 +01:00
BAIL_MACRO ( PHYSFS_ERR_READ_ONLY , 0 ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_remove */
2012-03-25 20:52:24 +02:00
static int LZMA_mkdir ( PHYSFS_Dir * opaque , const char * name )
2006-04-11 16:33:48 +02:00
{
2012-03-22 05:05:10 +01:00
BAIL_MACRO ( PHYSFS_ERR_READ_ONLY , 0 ) ;
2006-04-11 16:33:48 +02:00
} /* LZMA_mkdir */
2012-03-25 20:52:24 +02:00
static int LZMA_stat ( PHYSFS_Dir * opaque , const char * filename ,
int * exists , PHYSFS_Stat * stat )
2010-02-15 20:02:36 +01:00
{
const LZMAarchive * archive = ( const LZMAarchive * ) opaque ;
const LZMAfile * file = lzma_find_file ( archive , filename ) ;
* exists = ( file ! = 0 ) ;
if ( ! file )
return 0 ;
if ( file - > item - > IsDirectory )
{
stat - > filesize = 0 ;
stat - > filetype = PHYSFS_FILETYPE_DIRECTORY ;
} /* if */
else
{
stat - > filesize = ( PHYSFS_sint64 ) file - > item - > Size ;
stat - > filetype = PHYSFS_FILETYPE_REGULAR ;
} /* else */
/* !!! FIXME: the 0's should be -1's? */
if ( file - > item - > IsLastWriteTimeDefined )
stat - > modtime = lzma_filetime_to_unix_timestamp ( & file - > item - > LastWriteTime ) ;
else
stat - > modtime = 0 ;
/* real create and accesstype are currently not in the lzma SDK */
stat - > createtime = stat - > modtime ;
stat - > accesstime = 0 ;
stat - > readonly = 1 ; /* 7zips are always read only */
2010-08-22 01:10:42 +02:00
return 1 ;
2010-02-15 20:02:36 +01:00
} /* LZMA_stat */
2006-04-11 16:33:48 +02:00
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_LZMA =
{
" 7Z " ,
2012-03-23 05:55:56 +01:00
" LZMA (7zip) format " ,
2006-04-11 16:33:48 +02:00
" Dennis Schridde <devurandom@gmx.net> " ,
" http://icculus.org/physfs/ " ,
} ;
const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
{
& __PHYSFS_ArchiveInfo_LZMA ,
LZMA_openArchive , /* openArchive() method */
LZMA_enumerateFiles , /* enumerateFiles() method */
LZMA_openRead , /* openRead() method */
LZMA_openWrite , /* openWrite() method */
LZMA_openAppend , /* openAppend() method */
LZMA_remove , /* remove() method */
LZMA_mkdir , /* mkdir() method */
2012-03-24 15:36:11 +01:00
LZMA_closeArchive , /* closeArchive() method */
2010-08-30 09:01:57 +02:00
LZMA_stat /* stat() method */
2006-04-11 16:33:48 +02:00
} ;
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 ... */