2007-05-30 21:56:52 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
2004-10-15 06:06:47 +00:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2005-10-18 01:30:26 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2004-10-15 06:06:47 +00:00
*
2006-02-09 12:19:53 +00:00
* $ URL $
* $ Id $
2004-10-15 06:06:47 +00:00
*
*/
2007-09-19 08:40:12 +00:00
2006-07-15 20:30:36 +00:00
# include "common/config-manager.h"
2006-03-29 15:59:37 +00:00
# include "common/endian.h"
2004-10-15 06:06:47 +00:00
# include "common/file.h"
2006-07-15 20:30:36 +00:00
# include "common/fs.h"
2007-05-23 12:02:31 +00:00
# include "common/func.h"
2006-07-08 12:23:44 +00:00
2005-08-19 22:12:09 +00:00
# include "kyra/resource.h"
2004-10-15 06:06:47 +00:00
namespace Kyra {
2007-05-23 12:02:31 +00:00
2008-05-11 23:16:50 +00:00
Resource : : Resource ( KyraEngine_v1 * vm ) : _loaders ( ) , _map ( ) , _vm ( vm ) {
2008-02-07 23:13:13 +00:00
initializeLoaders ( ) ;
2007-10-09 05:40:20 +00:00
}
Resource : : ~ Resource ( ) {
2008-04-03 21:25:05 +00:00
_map . clear ( ) ;
2008-02-07 23:38:17 +00:00
_loaders . clear ( ) ;
2008-05-31 20:48:41 +00:00
clearCompFileList ( ) ;
_compLoaders . clear ( ) ;
2007-10-09 05:40:20 +00:00
}
bool Resource : : reset ( ) {
2008-05-31 20:48:41 +00:00
clearCompFileList ( ) ;
2007-10-09 05:40:20 +00:00
unloadAllPakFiles ( ) ;
FilesystemNode dir ( ConfMan . get ( " path " ) ) ;
2008-01-27 19:47:41 +00:00
2007-10-09 05:40:20 +00:00
if ( ! dir . exists ( ) | | ! dir . isDirectory ( ) )
error ( " invalid game path '%s' " , dir . getPath ( ) . c_str ( ) ) ;
2005-07-30 21:11:48 +00:00
2008-08-02 23:11:31 +00:00
if ( ! loadPakFile ( StaticResource : : staticDataFilename ( ) ) | | ! StaticResource : : checkKyraDat ( ) ) {
Common : : String errorMessage = " You're missing the ' " + StaticResource : : staticDataFilename ( ) + " ' file or it got corrupted, (re)get it from the ScummVM website " ;
_vm - > GUIErrorMessage ( errorMessage ) ;
error ( errorMessage . c_str ( ) ) ;
2008-01-10 23:25:19 +00:00
}
2006-07-15 20:30:36 +00:00
2008-01-10 23:25:19 +00:00
if ( _vm - > game ( ) = = GI_KYRA1 ) {
2006-07-15 20:32:54 +00:00
// We only need kyra.dat for the demo.
2007-04-01 13:10:50 +00:00
if ( _vm - > gameFlags ( ) . isDemo )
2007-10-09 05:40:20 +00:00
return true ;
2006-07-15 20:32:54 +00:00
2006-07-15 20:30:36 +00:00
// only VRM file we need in the *whole* game for kyra1
2007-04-01 13:10:50 +00:00
if ( _vm - > gameFlags ( ) . isTalkie )
2006-07-16 19:44:39 +00:00
loadPakFile ( " CHAPTER1.VRM " ) ;
2008-01-10 23:25:19 +00:00
} else if ( _vm - > game ( ) = = GI_KYRA2 ) {
2008-05-24 16:30:18 +00:00
if ( _vm - > gameFlags ( ) . useInstallerPackage )
2008-05-31 20:48:41 +00:00
tryLoadCompFiles ( ) ;
2008-05-24 16:30:18 +00:00
2008-01-10 23:25:19 +00:00
// mouse pointer, fonts, etc. required for initializing
2008-03-20 12:10:30 +00:00
if ( _vm - > gameFlags ( ) . isDemo & & ! _vm - > gameFlags ( ) . isTalkie ) {
2008-01-10 23:25:19 +00:00
loadPakFile ( " GENERAL.PAK " ) ;
} else {
2008-05-17 18:24:14 +00:00
if ( _vm - > gameFlags ( ) . isTalkie ) {
// Add default file directories
Common : : File : : addDefaultDirectory ( ConfMan . get ( " path " ) + " hof_cd " ) ;
Common : : File : : addDefaultDirectory ( ConfMan . get ( " path " ) + " HOF_CD " ) ;
}
2008-01-10 23:25:19 +00:00
loadPakFile ( " INTROGEN.PAK " ) ;
loadPakFile ( " OTHER.PAK " ) ;
}
return true ;
2007-04-01 13:10:50 +00:00
} else if ( _vm - > game ( ) = = GI_KYRA3 ) {
2008-08-05 12:13:01 +00:00
if ( _vm - > gameFlags ( ) . useInstallerPackage ) {
if ( ! loadPakFile ( " WESTWOOD.001 " ) )
error ( " couldn't load file: 'WESTWOOD.001' " ) ;
}
2008-05-31 20:48:41 +00:00
2008-05-17 18:24:14 +00:00
// Add default file directories
Common : : File : : addDefaultDirectory ( ConfMan . get ( " path " ) + " malcolm " ) ;
Common : : File : : addDefaultDirectory ( ConfMan . get ( " path " ) + " MALCOLM " ) ;
2008-08-05 12:13:01 +00:00
if ( ! loadFileList ( " FILEDATA.FDT " ) )
error ( " couldn't load file: 'FILEDATA.FDT' " ) ;
2008-04-12 23:17:21 +00:00
2008-07-31 10:47:15 +00:00
return true ;
} else if ( _vm - > game ( ) = = GI_LOL ) {
2008-08-11 14:47:50 +00:00
if ( _vm - > gameFlags ( ) . useInstallerPackage )
tryLoadCompFiles ( ) ;
2008-04-12 23:17:21 +00:00
return true ;
2006-05-28 04:08:25 +00:00
}
2006-07-15 20:32:54 +00:00
2006-07-15 20:30:36 +00:00
FSList fslist ;
2007-06-05 21:02:35 +00:00
if ( ! dir . getChildren ( fslist , FilesystemNode : : kListFilesOnly ) )
2007-10-09 05:40:20 +00:00
error ( " can't list files inside game path '%s' " , dir . getPath ( ) . c_str ( ) ) ;
2004-11-14 20:11:22 +00:00
2007-04-01 13:10:50 +00:00
if ( _vm - > game ( ) = = GI_KYRA1 & & _vm - > gameFlags ( ) . isTalkie ) {
2006-09-16 14:36:53 +00:00
static const char * list [ ] = {
2006-10-24 00:30:48 +00:00
" ADL.PAK " , " CHAPTER1.VRM " , " COL.PAK " , " FINALE.PAK " , " INTRO1.PAK " , " INTRO2.PAK " ,
" INTRO3.PAK " , " INTRO4.PAK " , " MISC.PAK " , " SND.PAK " , " STARTUP.PAK " , " XMI.PAK " ,
2007-05-23 12:02:31 +00:00
" CAVE.APK " , " DRAGON1.APK " , " DRAGON2.APK " , " LAGOON.APK "
2006-09-16 14:36:53 +00:00
} ;
2007-05-23 12:02:31 +00:00
Common : : for_each ( list , list + ARRAYSIZE ( list ) , Common : : bind1st ( Common : : mem_fun ( & Resource : : loadPakFile ) , this ) ) ;
2008-02-07 23:14:53 +00:00
for ( int i = 0 ; i < ARRAYSIZE ( list ) ; + + i ) {
ResFileMap : : iterator iterator = _map . find ( list [ i ] ) ;
if ( iterator ! = _map . end ( ) )
iterator - > _value . prot = true ;
}
2006-09-16 14:36:53 +00:00
} else {
for ( FSList : : const_iterator file = fslist . begin ( ) ; file ! = fslist . end ( ) ; + + file ) {
2007-06-05 21:02:35 +00:00
Common : : String filename = file - > getName ( ) ;
2006-09-16 14:36:53 +00:00
filename . toUppercase ( ) ;
2007-03-24 00:04:08 +00:00
// No real PAK file!
if ( filename = = " TWMUSIC.PAK " )
continue ;
2008-02-07 23:13:13 +00:00
if ( filename = = ( ( _vm - > gameFlags ( ) . lang = = Common : : EN_ANY ) ? " JMC.PAK " : " EMC.PAK " ) )
continue ;
if ( filename . hasSuffix ( " .PAK " ) | | filename . hasSuffix ( " .APK " ) ) {
2007-06-05 21:02:35 +00:00
if ( ! loadPakFile ( file - > getName ( ) ) )
error ( " couldn't open pakfile '%s' " , file - > getName ( ) . c_str ( ) ) ;
2006-07-15 20:37:32 +00:00
}
2006-07-15 20:30:36 +00:00
}
2004-10-15 06:06:47 +00:00
}
2005-07-30 21:11:48 +00:00
2007-10-09 05:40:20 +00:00
return true ;
2005-10-12 19:15:32 +00:00
}
2007-05-23 12:02:31 +00:00
bool Resource : : loadPakFile ( const Common : : String & filename ) {
2008-08-20 14:30:40 +00:00
if ( ! isAccessible ( filename ) )
2008-02-07 23:13:13 +00:00
return false ;
2006-07-08 13:56:56 +00:00
2008-04-10 22:18:47 +00:00
ResFileMap : : iterator iter = _map . find ( filename ) ;
2008-04-10 22:22:35 +00:00
if ( iter = = _map . end ( ) )
return false ;
if ( iter - > _value . preload ) {
2008-02-09 15:46:06 +00:00
iter - > _value . mounted = true ;
2008-02-09 15:33:04 +00:00
return true ;
2008-02-09 15:46:06 +00:00
}
2007-09-19 08:40:12 +00:00
2008-02-09 15:33:04 +00:00
const ResArchiveLoader * loader = getLoader ( iter - > _value . type ) ;
if ( ! loader ) {
error ( " no archive loader for file '%s' found which is of type %d " , filename . c_str ( ) , iter - > _value . type ) ;
2006-03-18 14:43:18 +00:00
return false ;
2008-02-09 15:33:04 +00:00
}
2006-07-08 13:56:56 +00:00
2008-02-09 15:33:04 +00:00
Common : : SeekableReadStream * stream = getFileStream ( filename ) ;
if ( ! stream ) {
error ( " archive file '%s' not found " , filename . c_str ( ) ) ;
return false ;
}
2008-02-07 23:13:13 +00:00
2008-02-09 15:46:06 +00:00
iter - > _value . mounted = true ;
2008-02-09 15:33:04 +00:00
iter - > _value . preload = true ;
2008-02-09 16:18:44 +00:00
ResArchiveLoader : : FileList files ;
loader - > loadFile ( filename , * stream , files ) ;
2008-02-07 23:13:13 +00:00
delete stream ;
stream = 0 ;
2008-02-09 16:18:44 +00:00
for ( ResArchiveLoader : : FileList : : iterator i = files . begin ( ) ; i ! = files . end ( ) ; + + i ) {
iter = _map . find ( i - > filename ) ;
if ( iter = = _map . end ( ) ) {
2008-08-14 22:09:36 +00:00
// We do an internal check for a file in gamepath with same filename to
// allow overwriting files inside archives with plain files inside the
2008-08-14 22:11:56 +00:00
// game directory
2008-08-14 22:09:36 +00:00
checkFile ( i - > filename ) ;
2008-02-09 16:27:49 +00:00
// A new file entry, so we just insert it into the file map.
2008-08-14 22:09:36 +00:00
if ( _map . find ( i - > filename ) = = _map . end ( ) )
_map [ i - > filename ] = i - > entry ;
2008-02-09 16:18:44 +00:00
} else if ( ! iter - > _value . parent . empty ( ) ) {
if ( ! iter - > _value . parent . equalsIgnoreCase ( filename ) ) {
ResFileMap : : iterator oldParent = _map . find ( iter - > _value . parent ) ;
if ( oldParent ! = _map . end ( ) ) {
2008-02-09 16:27:49 +00:00
// Protected files and their embedded file entries do not get overwritten.
2008-02-09 16:18:44 +00:00
if ( ! oldParent - > _value . prot ) {
2008-02-09 16:27:49 +00:00
// If the old parent is not protected we mark it as not preload anymore,
// since now no longer all of its embedded files are in the filemap.
2008-02-09 16:18:44 +00:00
oldParent - > _value . preload = false ;
2008-08-20 14:30:40 +00:00
iter - > _value = i - > entry ;
2008-02-09 16:18:44 +00:00
}
} else {
// Old parent not found? That's strange... But we just overwrite the old
// entry.
2008-08-20 14:30:40 +00:00
iter - > _value = i - > entry ;
2008-02-09 16:18:44 +00:00
}
} else {
2008-02-09 16:27:49 +00:00
// The old parent has the same filenames as the new archive, we are sure and overwrite the
// old file entry, could be afterall that the preload flag of the new archive was
// just unflagged.
2008-08-20 14:30:40 +00:00
iter - > _value = i - > entry ;
2008-02-09 16:18:44 +00:00
}
}
2008-02-09 16:27:49 +00:00
// 'else' case would mean here overwriting an existing file entry in the map without parent.
2008-02-09 16:18:44 +00:00
// We don't support that though, so one can overwrite files from archives by putting
// them in the gamepath.
}
2007-03-20 21:11:42 +00:00
2008-02-07 23:13:13 +00:00
detectFileTypes ( ) ;
2005-10-12 19:15:32 +00:00
return true ;
}
2007-10-09 05:40:20 +00:00
bool Resource : : loadFileList ( const Common : : String & filedata ) {
Common : : File f ;
2008-01-27 19:47:41 +00:00
2007-10-09 05:40:20 +00:00
if ( ! f . open ( filedata ) )
return false ;
uint32 filenameOffset = 0 ;
while ( ( filenameOffset = f . readUint32LE ( ) ) ! = 0 ) {
uint32 offset = f . pos ( ) ;
f . seek ( filenameOffset , SEEK_SET ) ;
2008-04-03 21:42:04 +00:00
uint8 buffer [ 13 ] ;
f . read ( buffer , sizeof ( buffer ) - 1 ) ;
buffer [ 12 ] = 0 ;
2007-10-09 05:40:20 +00:00
f . seek ( offset + 16 , SEEK_SET ) ;
2008-05-24 17:34:20 +00:00
Common : : String filename = Common : : String ( ( char * ) buffer ) ;
2007-10-09 05:42:52 +00:00
filename . toUppercase ( ) ;
2007-10-09 05:40:20 +00:00
if ( filename . hasSuffix ( " .PAK " ) ) {
2008-08-20 14:30:40 +00:00
if ( ! isAccessible ( filename ) & & _vm - > gameFlags ( ) . isDemo ) {
2008-03-20 11:55:52 +00:00
// the demo version supplied with Kyra3 does not
// contain all pak files listed in filedata.fdt
// so we don't do anything here if they are non
// existant.
2008-03-20 11:58:18 +00:00
} else if ( ! loadPakFile ( filename ) ) {
2007-10-09 05:40:20 +00:00
error ( " couldn't load file '%s' " , filename . c_str ( ) ) ;
return false ;
}
2008-01-27 19:47:41 +00:00
}
2007-10-09 05:40:20 +00:00
}
return true ;
}
2008-01-10 23:25:19 +00:00
bool Resource : : loadFileList ( const char * const * filelist , uint32 numFiles ) {
if ( ! filelist )
return false ;
while ( numFiles - - ) {
if ( ! loadPakFile ( filelist [ numFiles ] ) ) {
error ( " couldn't load file '%s' " , filelist [ numFiles ] ) ;
return false ;
}
}
return true ;
}
2006-06-03 18:30:07 +00:00
void Resource : : unloadPakFile ( const Common : : String & filename ) {
2008-02-07 23:13:13 +00:00
ResFileMap : : iterator iter = _map . find ( filename ) ;
if ( iter ! = _map . end ( ) ) {
if ( ! iter - > _value . prot )
2008-02-09 15:46:06 +00:00
iter - > _value . mounted = false ;
2008-02-07 23:13:13 +00:00
}
2005-10-12 19:15:32 +00:00
}
2008-05-31 20:48:41 +00:00
void Resource : : clearCompFileList ( ) {
for ( CompFileMap : : iterator i = _compFiles . begin ( ) ; i ! = _compFiles . end ( ) ; + + i )
delete [ ] i - > _value . data ;
_compFiles . clear ( ) ;
}
2008-04-10 22:18:47 +00:00
bool Resource : : isInPakList ( const Common : : String & filename ) {
2008-08-20 14:30:40 +00:00
if ( ! isAccessible ( filename ) )
2008-04-19 14:36:26 +00:00
return false ;
ResFileMap : : iterator iter = _map . find ( filename ) ;
if ( iter = = _map . end ( ) )
return false ;
2008-04-19 14:40:37 +00:00
return ( iter - > _value . type ! = ResFileEntry : : kRaw ) ;
2004-11-14 20:11:22 +00:00
}
2005-07-30 21:11:48 +00:00
2007-10-09 05:40:20 +00:00
void Resource : : unloadAllPakFiles ( ) {
2008-02-07 23:13:13 +00:00
// remove all entries
_map . clear ( ) ;
2008-02-24 12:30:12 +00:00
}
2008-04-10 22:18:47 +00:00
uint8 * Resource : : fileData ( const char * file , uint32 * size ) {
2008-02-07 23:13:13 +00:00
Common : : SeekableReadStream * stream = getFileStream ( file ) ;
if ( ! stream )
return 0 ;
2005-07-30 21:11:48 +00:00
2008-02-07 23:13:13 +00:00
uint32 bufferSize = stream - > size ( ) ;
uint8 * buffer = new uint8 [ bufferSize ] ;
assert ( buffer ) ;
2006-07-30 07:51:11 +00:00
if ( size )
2008-02-07 23:13:13 +00:00
* size = bufferSize ;
stream - > read ( buffer , bufferSize ) ;
delete stream ;
return buffer ;
}
2005-07-30 21:11:48 +00:00
2008-04-19 14:31:10 +00:00
bool Resource : : exists ( const char * file , bool errorOutOnFail ) {
if ( Common : : File : : exists ( file ) )
return true ;
2008-08-20 14:30:40 +00:00
else if ( isAccessible ( file ) )
2008-04-19 14:31:10 +00:00
return true ;
else if ( errorOutOnFail )
error ( " File '%s' can't be found " , file ) ;
return false ;
}
2008-04-10 22:18:47 +00:00
uint32 Resource : : getFileSize ( const char * file ) {
2008-05-31 20:48:41 +00:00
CompFileMap : : iterator compEntry ;
2008-04-19 14:31:10 +00:00
if ( Common : : File : : exists ( file ) ) {
Common : : File f ;
if ( f . open ( file ) )
return f . size ( ) ;
} else {
2008-08-20 14:30:40 +00:00
if ( ! isAccessible ( file ) )
2008-04-19 14:31:10 +00:00
return 0 ;
2006-09-16 20:51:05 +00:00
2008-04-19 14:31:10 +00:00
ResFileMap : : const_iterator iter = _map . find ( file ) ;
if ( iter ! = _map . end ( ) )
return iter - > _value . size ;
}
2008-02-07 23:13:13 +00:00
return 0 ;
}
2006-07-30 07:51:11 +00:00
2008-02-07 23:13:13 +00:00
bool Resource : : loadFileToBuf ( const char * file , void * buf , uint32 maxSize ) {
Common : : SeekableReadStream * stream = getFileStream ( file ) ;
if ( ! stream )
return false ;
2007-07-02 23:02:54 +00:00
2008-02-07 23:13:13 +00:00
memset ( buf , 0 , maxSize ) ;
2008-05-31 20:48:41 +00:00
stream - > read ( buf , ( maxSize < = stream - > size ( ) ) ? maxSize : stream - > size ( ) ) ;
2008-02-07 23:13:13 +00:00
delete stream ;
return true ;
}
2007-07-02 23:02:54 +00:00
2008-04-10 22:18:47 +00:00
Common : : SeekableReadStream * Resource : : getFileStream ( const Common : : String & file ) {
2008-05-31 20:48:41 +00:00
CompFileMap : : iterator compEntry ;
2008-08-14 22:09:36 +00:00
if ( ( compEntry = _compFiles . find ( file ) ) ! = _compFiles . end ( ) )
return new Common : : MemoryReadStream ( compEntry - > _value . data , compEntry - > _value . size , false ) ;
2008-08-20 14:30:40 +00:00
if ( ! isAccessible ( file ) )
2008-08-14 22:09:36 +00:00
return 0 ;
ResFileMap : : const_iterator iter = _map . find ( file ) ;
if ( iter = = _map . end ( ) )
return 0 ;
if ( iter - > _value . parent . empty ( ) ) {
2008-04-19 14:31:10 +00:00
Common : : File * stream = new Common : : File ( ) ;
if ( ! stream - > open ( file ) ) {
delete stream ;
stream = 0 ;
error ( " Couldn't open file '%s' " , file . c_str ( ) ) ;
}
2008-04-18 19:11:58 +00:00
return stream ;
} else {
2008-08-14 22:09:36 +00:00
Common : : SeekableReadStream * parent = getFileStream ( iter - > _value . parent ) ;
assert ( parent ) ;
2008-04-19 14:31:10 +00:00
2008-08-20 14:30:40 +00:00
ResFileEntry * parentEntry = getParentEntry ( & iter - > _value ) ;
const ResArchiveLoader * loader = getLoader ( parentEntry - > type ) ;
2008-08-14 22:09:36 +00:00
assert ( loader ) ;
2008-04-19 14:31:10 +00:00
2008-08-14 22:09:36 +00:00
return loader - > loadFileFromArchive ( file , parent , iter - > _value ) ;
2004-11-14 20:11:22 +00:00
}
2005-07-30 21:11:48 +00:00
2007-03-20 20:46:19 +00:00
return 0 ;
2004-11-14 20:11:22 +00:00
}
2005-07-30 21:11:48 +00:00
2008-08-20 14:30:40 +00:00
bool Resource : : isAccessible ( const Common : : String & file ) {
2008-04-10 22:18:47 +00:00
checkFile ( file ) ;
2008-02-07 23:13:13 +00:00
ResFileMap : : const_iterator iter = _map . find ( file ) ;
2008-08-20 14:30:40 +00:00
if ( iter = = _map . end ( ) )
return false ;
return isAccessible ( & iter - > _value ) ;
}
bool Resource : : isAccessible ( const ResFileEntry * fileEntry ) {
assert ( fileEntry ) ;
const ResFileEntry * currentEntry = fileEntry ;
2008-08-20 14:56:46 +00:00
while ( ! currentEntry - > parent . empty ( ) ) {
2008-08-20 14:30:40 +00:00
if ( currentEntry - > parentEntry ) {
currentEntry = currentEntry - > parentEntry ;
2008-02-09 15:46:06 +00:00
} else {
2008-08-20 14:30:40 +00:00
ResFileMap : : iterator it = _map . find ( currentEntry - > parent ) ;
if ( it = = _map . end ( ) )
return false ;
else
currentEntry - > parentEntry = & it - > _value ;
2008-02-09 15:46:06 +00:00
}
2008-08-20 14:30:40 +00:00
// parent can never be a non archive file
if ( currentEntry - > type = = ResFileEntry : : kRaw )
return false ;
// not mounted parent means not accessable
else if ( ! currentEntry - > mounted )
return false ;
2006-02-10 16:39:56 +00:00
}
2008-08-20 14:30:40 +00:00
return true ;
}
ResFileEntry * Resource : : getParentEntry ( const ResFileEntry * entry ) const {
assert ( entry ) ;
if ( entry - > parent . empty ( ) ) {
return 0 ;
} else if ( entry - > parentEntry ) {
assert ( _map . find ( entry - > parent ) ! = _map . end ( ) ) ; // If some day the hash map implementations changes and moves nodes around,
// this assumption would fail and the whole system would need a refactoring
assert ( entry - > parentEntry = = & _map . find ( entry - > parent ) - > _value ) ;
return entry - > parentEntry ;
} else {
ResFileMap : : iterator it = _map . find ( entry - > parent ) ;
if ( it = = _map . end ( ) )
return 0 ; // If it happens often, the structure maybe deserves a flag to avoid rechecking the map
else {
entry - > parentEntry = & it - > _value ;
return entry - > parentEntry ;
}
}
}
ResFileEntry * Resource : : getParentEntry ( const Common : : String & filename ) const {
ResFileMap : : iterator it = _map . find ( filename ) ;
assert ( it ! = _map . end ( ) ) ;
return getParentEntry ( & it - > _value ) ;
2006-02-10 16:39:56 +00:00
}
2008-04-10 22:18:47 +00:00
void Resource : : checkFile ( const Common : : String & file ) {
2008-05-31 20:48:41 +00:00
if ( _map . find ( file ) = = _map . end ( ) ) {
CompFileMap : : const_iterator iter ;
2008-08-14 22:09:36 +00:00
if ( ( iter = _compFiles . find ( file ) ) ! = _compFiles . end ( ) ) {
2008-08-20 14:30:40 +00:00
ResFileEntry & entry = _map [ file ] ;
2008-08-14 22:09:36 +00:00
entry . parent = " " ;
2008-08-20 14:30:40 +00:00
entry . parentEntry = 0 ;
2008-08-14 22:09:36 +00:00
entry . size = iter - > _value . size ;
entry . mounted = false ;
entry . preload = false ;
entry . prot = false ;
entry . type = ResFileEntry : : kAutoDetect ;
entry . offset = 0 ;
2008-08-20 14:30:40 +00:00
detectFileType ( file , & entry ) ;
2008-08-14 22:09:36 +00:00
} else if ( Common : : File : : exists ( file ) ) {
2008-05-31 20:48:41 +00:00
Common : : File temp ;
if ( temp . open ( file ) ) {
2008-08-20 14:30:40 +00:00
ResFileEntry & entry = _map [ file ] ;
2008-05-31 20:48:41 +00:00
entry . parent = " " ;
2008-08-20 14:30:40 +00:00
entry . parentEntry = 0 ;
2008-05-31 20:48:41 +00:00
entry . size = temp . size ( ) ;
entry . mounted = file . compareToIgnoreCase ( StaticResource : : staticDataFilename ( ) ) ! = 0 ;
entry . preload = false ;
entry . prot = false ;
entry . type = ResFileEntry : : kAutoDetect ;
entry . offset = 0 ;
temp . close ( ) ;
2008-08-20 14:30:40 +00:00
detectFileType ( file , & entry ) ;
2008-05-31 20:48:41 +00:00
}
2008-04-10 22:18:47 +00:00
}
}
}
2008-08-20 14:30:40 +00:00
void Resource : : detectFileType ( const Common : : String & filename , ResFileEntry * fileEntry ) {
assert ( fileEntry ) ;
if ( ! isAccessible ( fileEntry ) )
return ;
2007-09-19 08:40:12 +00:00
2008-08-20 14:30:40 +00:00
if ( fileEntry - > type = = ResFileEntry : : kAutoDetect ) {
Common : : SeekableReadStream * stream = 0 ;
for ( LoaderIterator l = _loaders . begin ( ) ; l ! = _loaders . end ( ) ; + + l ) {
if ( ! ( * l ) - > checkFilename ( filename ) )
continue ;
if ( ! stream )
stream = getFileStream ( filename ) ;
if ( ( * l ) - > isLoadable ( filename , * stream ) ) {
fileEntry - > type = ( * l ) - > getType ( ) ;
fileEntry - > mounted = false ;
fileEntry - > preload = false ;
break ;
}
2008-02-07 23:13:13 +00:00
}
2008-08-20 14:30:40 +00:00
delete stream ;
stream = 0 ;
if ( fileEntry - > type = = ResFileEntry : : kAutoDetect )
fileEntry - > type = ResFileEntry : : kRaw ;
2006-07-31 16:37:34 +00:00
}
}
2008-08-20 14:30:40 +00:00
void Resource : : detectFileTypes ( ) {
for ( ResFileMap : : iterator i = _map . begin ( ) ; i ! = _map . end ( ) ; + + i )
detectFileType ( i - > _key , & i - > _value ) ;
}
2008-05-31 20:48:41 +00:00
void Resource : : tryLoadCompFiles ( ) {
for ( CCompLoaderIterator i = _compLoaders . begin ( ) ; i ! = _compLoaders . end ( ) ; + + i ) {
if ( ( * i ) - > checkForFiles ( ) )
( * i ) - > loadFile ( _compFiles ) ;
}
}
2008-02-07 23:13:13 +00:00
# pragma mark -
# pragma mark - ResFileLodaer
# pragma mark -
2006-07-31 16:37:34 +00:00
2008-02-07 23:13:13 +00:00
class ResLoaderPak : public ResArchiveLoader {
public :
2008-02-09 15:18:35 +00:00
bool checkFilename ( Common : : String filename ) const ;
2008-02-07 23:13:13 +00:00
bool isLoadable ( const Common : : String & filename , Common : : SeekableReadStream & stream ) const ;
2008-02-09 16:18:44 +00:00
bool loadFile ( const Common : : String & filename , Common : : SeekableReadStream & stream , FileList & files ) const ;
Common : : SeekableReadStream * loadFileFromArchive ( const Common : : String & file , Common : : SeekableReadStream * archive , const ResFileEntry entry ) const ;
2006-07-31 16:37:34 +00:00
2008-02-07 23:13:13 +00:00
ResFileEntry : : kType getType ( ) const {
return ResFileEntry : : kPak ;
}
} ;
2006-07-31 16:37:34 +00:00
2008-02-09 15:18:35 +00:00
bool ResLoaderPak : : checkFilename ( Common : : String filename ) const {
filename . toUppercase ( ) ;
return ( filename . hasSuffix ( " .PAK " ) | | filename . hasSuffix ( " .APK " ) | | filename . hasSuffix ( " .VRM " ) | | filename . hasSuffix ( " .TLK " ) | | filename . equalsIgnoreCase ( StaticResource : : staticDataFilename ( ) ) ) ;
}
2008-02-07 23:13:13 +00:00
bool ResLoaderPak : : isLoadable ( const Common : : String & filename , Common : : SeekableReadStream & stream ) const {
2008-02-09 15:08:49 +00:00
uint32 filesize = stream . size ( ) ;
uint32 offset = 0 ;
bool switchEndian = false ;
bool firstFile = true ;
offset = stream . readUint32LE ( ) ;
if ( offset > filesize ) {
switchEndian = true ;
offset = SWAP_BYTES_32 ( offset ) ;
}
2008-04-03 21:42:04 +00:00
Common : : String file = " " ;
2008-02-09 15:08:49 +00:00
while ( ! stream . eos ( ) ) {
// The start offset of a file should never be in the filelist
if ( offset < stream . pos ( ) | | offset > filesize )
return false ;
byte c = 0 ;
2008-04-03 21:42:04 +00:00
file = " " ;
2008-02-09 15:08:49 +00:00
while ( ! stream . eos ( ) & & ( c = stream . readByte ( ) ) ! = 0 )
file + = c ;
if ( stream . eos ( ) )
return false ;
// Quit now if we encounter an empty string
if ( file . empty ( ) ) {
if ( firstFile )
return false ;
else
break ;
}
firstFile = false ;
offset = switchEndian ? stream . readUint32BE ( ) : stream . readUint32LE ( ) ;
if ( ! offset | | offset = = filesize )
break ;
}
return true ;
2006-07-31 16:37:34 +00:00
}
2008-06-03 18:12:21 +00:00
namespace {
Common : : String readString ( Common : : SeekableReadStream & stream ) {
Common : : String result ;
char c = 0 ;
while ( ( c = stream . readByte ( ) ) ! = 0 )
result + = c ;
return result ;
}
} // end of anonymous namespace
2008-02-09 16:18:44 +00:00
bool ResLoaderPak : : loadFile ( const Common : : String & filename , Common : : SeekableReadStream & stream , FileList & files ) const {
2008-02-07 23:13:13 +00:00
uint32 filesize = stream . size ( ) ;
2008-02-09 14:40:52 +00:00
uint32 startoffset = 0 , endoffset = 0 ;
2008-02-07 23:13:13 +00:00
bool switchEndian = false ;
2008-02-09 15:08:49 +00:00
bool firstFile = true ;
2004-10-15 06:06:47 +00:00
2008-02-09 14:40:52 +00:00
startoffset = stream . readUint32LE ( ) ;
2007-03-20 21:11:42 +00:00
if ( startoffset > filesize ) {
2008-02-07 23:13:13 +00:00
switchEndian = true ;
startoffset = SWAP_BYTES_32 ( startoffset ) ;
2006-03-14 19:48:08 +00:00
}
2007-03-20 21:11:42 +00:00
2008-04-03 21:42:04 +00:00
Common : : String file = " " ;
2008-02-09 14:40:52 +00:00
while ( ! stream . eos ( ) ) {
2008-02-09 14:43:43 +00:00
// The start offset of a file should never be in the filelist
2008-02-09 15:08:49 +00:00
if ( startoffset < stream . pos ( ) | | startoffset > filesize ) {
2008-02-09 14:43:43 +00:00
warning ( " PAK file '%s' is corrupted " , filename . c_str ( ) ) ;
return false ;
}
2008-04-03 21:42:04 +00:00
file = " " ;
2008-02-09 14:40:52 +00:00
byte c = 0 ;
2007-09-19 08:40:12 +00:00
2008-02-09 14:40:52 +00:00
while ( ! stream . eos ( ) & & ( c = stream . readByte ( ) ) ! = 0 )
file + = c ;
2007-09-19 08:40:12 +00:00
2008-02-09 14:40:52 +00:00
if ( stream . eos ( ) ) {
2008-02-07 23:13:13 +00:00
warning ( " PAK file '%s' is corrupted " , filename . c_str ( ) ) ;
return false ;
2007-03-20 21:11:42 +00:00
}
2007-09-19 08:40:12 +00:00
2006-09-09 12:21:49 +00:00
// Quit now if we encounter an empty string
2008-02-09 15:08:49 +00:00
if ( file . empty ( ) ) {
if ( firstFile ) {
warning ( " PAK file '%s' is corrupted " , filename . c_str ( ) ) ;
return false ;
} else {
break ;
}
}
2006-08-08 21:34:19 +00:00
2008-02-09 15:08:49 +00:00
firstFile = false ;
2008-02-09 14:40:52 +00:00
endoffset = switchEndian ? stream . readUint32BE ( ) : stream . readUint32LE ( ) ;
2005-07-30 21:11:48 +00:00
2008-02-07 23:13:13 +00:00
if ( ! endoffset )
2004-11-14 20:11:22 +00:00
endoffset = filesize ;
2004-10-15 06:06:47 +00:00
2007-03-20 21:11:42 +00:00
if ( startoffset ! = endoffset ) {
2008-02-07 23:13:13 +00:00
ResFileEntry entry ;
entry . size = endoffset - startoffset ;
entry . offset = startoffset ;
entry . parent = filename ;
2008-08-20 14:30:40 +00:00
entry . parentEntry = 0 ;
2008-02-07 23:13:13 +00:00
entry . type = ResFileEntry : : kAutoDetect ;
2008-02-09 15:46:06 +00:00
entry . mounted = false ;
2008-02-07 23:13:13 +00:00
entry . prot = false ;
entry . preload = false ;
2008-02-09 16:18:44 +00:00
files . push_back ( File ( file , entry ) ) ;
2007-03-20 21:11:42 +00:00
}
2005-07-30 21:11:48 +00:00
2004-11-14 20:11:22 +00:00
if ( endoffset = = filesize )
break ;
2004-11-11 13:37:35 +00:00
2004-11-14 20:11:22 +00:00
startoffset = endoffset ;
2004-10-16 22:28:29 +00:00
}
2006-07-08 13:56:56 +00:00
2008-06-03 18:12:21 +00:00
FileList : : const_iterator iter = Common : : find ( files . begin ( ) , files . end ( ) , Common : : String ( " LINKLIST " ) ) ;
if ( iter ! = files . end ( ) ) {
stream . seek ( iter - > entry . offset , SEEK_SET ) ;
uint32 magic = stream . readUint32BE ( ) ;
if ( magic ! = MKID_BE ( ' SCVM ' ) )
error ( " LINKLIST file does not contain 'SCVM' header " ) ;
uint32 links = stream . readUint32BE ( ) ;
for ( uint i = 0 ; i < links ; + + i ) {
Common : : String linksTo = readString ( stream ) ;
uint32 sources = stream . readUint32BE ( ) ;
iter = Common : : find ( files . begin ( ) , files . end ( ) , linksTo ) ;
if ( iter = = files . end ( ) )
error ( " PAK file link destination '%s' not found " , linksTo . c_str ( ) ) ;
for ( uint j = 0 ; j < sources ; + + j ) {
Common : : String dest = readString ( stream ) ;
files . push_back ( File ( dest , iter - > entry ) ) ;
// Better safe than sorry, we update the 'iter' value, in case push_back invalidated it
iter = Common : : find ( files . begin ( ) , files . end ( ) , linksTo ) ;
}
}
}
2008-02-07 23:13:13 +00:00
return true ;
2004-11-14 20:11:22 +00:00
}
2004-10-15 06:06:47 +00:00
2008-02-09 16:18:44 +00:00
Common : : SeekableReadStream * ResLoaderPak : : loadFileFromArchive ( const Common : : String & file , Common : : SeekableReadStream * archive , const ResFileEntry entry ) const {
2008-02-07 23:13:13 +00:00
assert ( archive ) ;
2007-05-23 12:02:31 +00:00
2008-02-09 16:18:44 +00:00
archive - > seek ( entry . offset , SEEK_SET ) ;
Common : : SeekableSubReadStream * stream = new Common : : SeekableSubReadStream ( archive , entry . offset , entry . offset + entry . size , true ) ;
2008-02-07 23:13:13 +00:00
assert ( stream ) ;
return stream ;
2004-11-14 20:11:22 +00:00
}
2004-10-15 06:06:47 +00:00
2008-05-31 20:48:41 +00:00
class ResLoaderInsMalcolm : public ResArchiveLoader {
2008-05-24 16:30:18 +00:00
public :
bool checkFilename ( Common : : String filename ) const ;
bool isLoadable ( const Common : : String & filename , Common : : SeekableReadStream & stream ) const ;
bool loadFile ( const Common : : String & filename , Common : : SeekableReadStream & stream , FileList & files ) const ;
Common : : SeekableReadStream * loadFileFromArchive ( const Common : : String & file , Common : : SeekableReadStream * archive , const ResFileEntry entry ) const ;
ResFileEntry : : kType getType ( ) const {
2008-05-31 20:48:41 +00:00
return ResFileEntry : : kInsMal ;
2008-05-24 16:30:18 +00:00
}
} ;
2008-05-31 20:48:41 +00:00
bool ResLoaderInsMalcolm : : checkFilename ( Common : : String filename ) const {
filename . toUppercase ( ) ;
if ( ! filename . hasSuffix ( " .001 " ) )
return false ;
return true ;
2008-05-24 16:30:18 +00:00
}
2008-05-31 20:48:41 +00:00
bool ResLoaderInsMalcolm : : isLoadable ( const Common : : String & filename , Common : : SeekableReadStream & stream ) const {
stream . seek ( 3 ) ;
uint32 size = stream . readUint32LE ( ) ;
if ( size + 7 > stream . size ( ) )
return false ;
stream . seek ( size + 5 , SEEK_SET ) ;
uint8 buffer [ 2 ] ;
stream . read ( & buffer , 2 ) ;
return ( buffer [ 0 ] = = 0x0D & & buffer [ 1 ] = = 0x0A ) ;
}
bool ResLoaderInsMalcolm : : loadFile ( const Common : : String & filename , Common : : SeekableReadStream & stream , FileList & files ) const {
Common : : List < Common : : String > filenames ;
// thanks to eriktorbjorn for this code (a bit modified though)
stream . seek ( 3 , SEEK_SET ) ;
// first file is the index table
uint32 size = stream . readUint32LE ( ) ;
Common : : String temp = " " ;
for ( uint32 i = 0 ; i < size ; + + i ) {
byte c = stream . readByte ( ) ;
if ( c = = ' \\ ' ) {
temp = " " ;
} else if ( c = = 0x0D ) {
// line endings are CRLF
c = stream . readByte ( ) ;
assert ( c = = 0x0A ) ;
+ + i ;
filenames . push_back ( temp ) ;
} else {
temp + = ( char ) c ;
}
}
stream . seek ( 3 , SEEK_SET ) ;
for ( Common : : List < Common : : String > : : iterator file = filenames . begin ( ) ; file ! = filenames . end ( ) ; + + file ) {
ResFileEntry entry ;
entry . parent = filename ;
2008-08-20 14:30:40 +00:00
entry . parentEntry = 0 ;
2008-05-31 20:48:41 +00:00
entry . type = ResFileEntry : : kAutoDetect ;
entry . mounted = false ;
entry . preload = false ;
entry . prot = false ;
entry . size = stream . readUint32LE ( ) ;
entry . offset = stream . pos ( ) ;
stream . seek ( entry . size , SEEK_CUR ) ;
files . push_back ( File ( * file , entry ) ) ;
}
2008-05-24 16:30:18 +00:00
return true ;
}
2008-05-31 20:48:41 +00:00
Common : : SeekableReadStream * ResLoaderInsMalcolm : : loadFileFromArchive ( const Common : : String & file , Common : : SeekableReadStream * archive , const ResFileEntry entry ) const {
assert ( archive ) ;
archive - > seek ( entry . offset , SEEK_SET ) ;
Common : : SeekableSubReadStream * stream = new Common : : SeekableSubReadStream ( archive , entry . offset , entry . offset + entry . size , true ) ;
assert ( stream ) ;
return stream ;
}
class ResLoaderTlk : public ResArchiveLoader {
public :
bool checkFilename ( Common : : String filename ) const ;
bool isLoadable ( const Common : : String & filename , Common : : SeekableReadStream & stream ) const ;
bool loadFile ( const Common : : String & filename , Common : : SeekableReadStream & stream , FileList & files ) const ;
Common : : SeekableReadStream * loadFileFromArchive ( const Common : : String & file , Common : : SeekableReadStream * archive , const ResFileEntry entry ) const ;
ResFileEntry : : kType getType ( ) const {
return ResFileEntry : : kTlk ;
}
private :
static bool sortTlkFileList ( const File & l , const File & r ) ;
static FileList : : const_iterator nextFile ( const FileList & list , FileList : : const_iterator iter ) ;
} ;
bool ResLoaderTlk : : checkFilename ( Common : : String filename ) const {
filename . toUppercase ( ) ;
return ( filename . hasSuffix ( " .TLK " ) ) ;
}
bool ResLoaderTlk : : isLoadable ( const Common : : String & filename , Common : : SeekableReadStream & stream ) const {
uint16 entries = stream . readUint16LE ( ) ;
uint32 entryTableSize = ( entries * 8 ) ;
if ( entryTableSize + 2 > stream . size ( ) )
return false ;
uint32 offset = 0 ;
for ( uint i = 0 ; i < entries ; + + i ) {
stream . readUint32LE ( ) ;
offset = stream . readUint32LE ( ) ;
if ( offset > stream . size ( ) )
return false ;
}
2008-05-24 16:30:18 +00:00
return true ;
}
2008-05-31 20:48:41 +00:00
bool ResLoaderTlk : : loadFile ( const Common : : String & filename , Common : : SeekableReadStream & stream , FileList & files ) const {
uint16 entries = stream . readUint16LE ( ) ;
for ( uint i = 0 ; i < entries ; + + i ) {
ResFileEntry entry ;
entry . parent = filename ;
2008-08-20 14:30:40 +00:00
entry . parentEntry = 0 ;
2008-05-31 20:48:41 +00:00
entry . type = ResFileEntry : : kAutoDetect ;
entry . mounted = false ;
entry . preload = false ;
entry . prot = false ;
uint32 resFilename = stream . readUint32LE ( ) ;
uint32 resOffset = stream . readUint32LE ( ) ;
entry . offset = resOffset + 4 ;
char realFilename [ 20 ] ;
2008-06-03 18:12:21 +00:00
snprintf ( realFilename , 20 , " %.08u.AUD " , resFilename ) ;
2008-05-31 20:48:41 +00:00
uint32 curOffset = stream . pos ( ) ;
stream . seek ( resOffset , SEEK_SET ) ;
entry . size = stream . readUint32LE ( ) ;
stream . seek ( curOffset , SEEK_SET ) ;
files . push_back ( FileList : : value_type ( realFilename , entry ) ) ;
}
return true ;
2008-05-24 16:30:18 +00:00
}
2008-05-31 20:48:41 +00:00
Common : : SeekableReadStream * ResLoaderTlk : : loadFileFromArchive ( const Common : : String & file , Common : : SeekableReadStream * archive , const ResFileEntry entry ) const {
assert ( archive ) ;
archive - > seek ( entry . offset , SEEK_SET ) ;
Common : : SeekableSubReadStream * stream = new Common : : SeekableSubReadStream ( archive , entry . offset , entry . offset + entry . size , true ) ;
assert ( stream ) ;
return stream ;
}
# pragma mark -
# pragma mark - CompFileLoader
# pragma mark -
2008-05-24 16:30:18 +00:00
class FileExpanderSource {
public :
2008-06-01 13:19:45 +00:00
FileExpanderSource ( const uint8 * data , int dataSize ) : _dataPtr ( data ) , _endofBuffer ( data + dataSize ) , _bitsLeft ( 8 ) , _key ( 0 ) , _index ( 0 ) { }
2008-05-24 16:30:18 +00:00
~ FileExpanderSource ( ) { }
void advSrcRefresh ( ) ;
void advSrcBitsBy1 ( ) ;
void advSrcBitsByIndex ( uint8 newIndex ) ;
uint8 getKeyLower ( ) { return _key & 0xff ; }
void setIndex ( uint8 index ) { _index = index ; }
uint16 getKeyMasked ( uint8 newIndex ) ;
uint16 keyMaskedAlign ( uint16 val ) ;
void copyBytes ( uint8 * & dst ) ;
private :
const uint8 * _dataPtr ;
2008-06-01 13:19:45 +00:00
const uint8 * _endofBuffer ;
2008-05-24 16:30:18 +00:00
uint16 _key ;
int8 _bitsLeft ;
uint8 _index ;
} ;
void FileExpanderSource : : advSrcBitsBy1 ( ) {
_key > > = 1 ;
if ( ! - - _bitsLeft ) {
2008-06-01 13:19:45 +00:00
if ( _dataPtr < _endofBuffer )
_key = ( ( * _dataPtr + + ) < < 8 ) | ( _key & 0xff ) ;
2008-05-24 16:30:18 +00:00
_bitsLeft = 8 ;
}
}
void FileExpanderSource : : advSrcBitsByIndex ( uint8 newIndex ) {
_index = newIndex ;
_bitsLeft - = _index ;
if ( _bitsLeft < = 0 ) {
_key > > = ( _index + _bitsLeft ) ;
_index = - _bitsLeft ;
_bitsLeft = 8 - _index ;
2008-06-01 13:19:45 +00:00
if ( _dataPtr < _endofBuffer )
_key = ( * _dataPtr + + < < 8 ) | ( _key & 0xff ) ;
2008-05-24 16:30:18 +00:00
}
_key > > = _index ;
}
uint16 FileExpanderSource : : getKeyMasked ( uint8 newIndex ) {
static const uint8 mskTable [ ] = { 0x0F , 0x01 , 0x03 , 0x07 , 0x0F , 0x1F , 0x3F , 0x7F , 0xFF } ;
_index = newIndex ;
uint16 res = 0 ;
if ( _index > 8 ) {
newIndex = _index - 8 ;
res = ( _key & 0xff ) & mskTable [ 8 ] ;
advSrcBitsByIndex ( 8 ) ;
_index = newIndex ;
res | = ( ( ( _key & 0xff ) & mskTable [ _index ] ) < < 8 ) ;
advSrcBitsByIndex ( _index ) ;
} else {
res = ( _key & 0xff ) & mskTable [ _index ] ;
advSrcBitsByIndex ( _index ) ;
}
return res ;
}
void FileExpanderSource : : copyBytes ( uint8 * & dst ) {
advSrcBitsByIndex ( _bitsLeft ) ;
uint16 r = ( READ_LE_UINT16 ( _dataPtr ) ^ _key ) + 1 ;
_dataPtr + = 2 ;
if ( r )
error ( " decompression failure " ) ;
memcpy ( dst , _dataPtr , _key ) ;
_dataPtr + = _key ;
dst + = _key ;
}
uint16 FileExpanderSource : : keyMaskedAlign ( uint16 val ) {
val - = 0x101 ;
_index = ( val & 0xff ) > > 2 ;
int16 b = ( ( _bitsLeft < < 8 ) | _index ) - 1 ;
_bitsLeft = b > > 8 ;
_index = b & 0xff ;
2008-06-01 15:11:08 +00:00
uint16 res = ( ( ( val & 3 ) + 4 ) < < _index ) + 0x101 ;
return res + getKeyMasked ( _index ) ;
2008-05-24 16:30:18 +00:00
}
void FileExpanderSource : : advSrcRefresh ( ) {
_key = READ_LE_UINT16 ( _dataPtr ) ;
2008-06-01 13:19:45 +00:00
if ( _dataPtr < _endofBuffer - 1 )
_dataPtr + = 2 ;
2008-05-24 16:30:18 +00:00
_bitsLeft = 8 ;
}
class FileExpander {
public :
FileExpander ( ) ;
~ FileExpander ( ) ;
2008-05-24 17:34:20 +00:00
bool process ( uint8 * dst , const uint8 * src , uint32 outsize , uint32 insize ) ;
2008-05-24 16:30:18 +00:00
private :
void generateTables ( uint8 srcIndex , uint8 dstIndex , uint8 dstIndex2 , int cnt ) ;
uint8 calcCmdAndIndex ( const uint8 * tbl , int16 & para ) ;
FileExpanderSource * _src ;
uint8 * _tables [ 9 ] ;
uint16 * _tables16 [ 3 ] ;
} ;
FileExpander : : FileExpander ( ) : _src ( 0 ) {
_tables [ 0 ] = new uint8 [ 3914 ] ;
assert ( _tables [ 0 ] ) ;
2008-05-24 19:07:44 +00:00
_tables [ 1 ] = _tables [ 0 ] + 320 ;
_tables [ 2 ] = _tables [ 0 ] + 352 ;
_tables [ 3 ] = _tables [ 0 ] + 864 ;
_tables [ 4 ] = _tables [ 0 ] + 2016 ;
_tables [ 5 ] = _tables [ 0 ] + 2528 ;
_tables [ 6 ] = _tables [ 0 ] + 2656 ;
_tables [ 7 ] = _tables [ 0 ] + 2736 ;
_tables [ 8 ] = _tables [ 0 ] + 2756 ;
_tables16 [ 0 ] = ( uint16 * ) ( _tables [ 0 ] + 3268 ) ;
_tables16 [ 1 ] = ( uint16 * ) ( _tables [ 0 ] + 3302 ) ;
_tables16 [ 2 ] = ( uint16 * ) ( _tables [ 0 ] + 3338 ) ;
2008-05-24 16:30:18 +00:00
}
FileExpander : : ~ FileExpander ( ) {
delete _src ;
2008-05-24 19:07:44 +00:00
delete [ ] _tables [ 0 ] ;
2008-05-24 16:30:18 +00:00
}
2008-05-24 17:34:20 +00:00
bool FileExpander : : process ( uint8 * dst , const uint8 * src , uint32 outsize , uint32 compressedSize ) {
2008-05-24 16:30:18 +00:00
static const uint8 indexTable [ ] = {
0x10 , 0x11 , 0x12 , 0x00 , 0x08 , 0x07 , 0x09 , 0x06 , 0x0A ,
0x05 , 0x0B , 0x04 , 0x0C , 0x03 , 0x0D , 0x02 , 0x0E , 0x01 , 0x0F
} ;
memset ( _tables [ 0 ] , 0 , 3914 ) ;
2008-05-24 17:34:20 +00:00
uint8 * d = dst ;
2008-05-24 16:30:18 +00:00
uint16 tableSize0 = 0 ;
uint16 tableSize1 = 0 ;
bool needrefresh = true ;
bool postprocess = false ;
2008-06-01 13:19:45 +00:00
_src = new FileExpanderSource ( src , compressedSize ) ;
2008-05-24 16:30:18 +00:00
while ( d < dst + outsize ) {
if ( needrefresh ) {
needrefresh = false ;
_src - > advSrcRefresh ( ) ;
}
_src - > advSrcBitsBy1 ( ) ;
int mode = _src - > getKeyMasked ( 2 ) - 1 ;
if ( mode = = 1 ) {
tableSize0 = _src - > getKeyMasked ( 5 ) + 257 ;
tableSize1 = _src - > getKeyMasked ( 5 ) + 1 ;
memset ( _tables [ 7 ] , 0 , 19 ) ;
2008-05-24 17:34:20 +00:00
const uint8 * itbl = indexTable ;
2008-05-24 16:30:18 +00:00
int numbytes = _src - > getKeyMasked ( 4 ) + 4 ;
while ( numbytes - - )
_tables [ 7 ] [ * itbl + + ] = _src - > getKeyMasked ( 3 ) ;
generateTables ( 7 , 8 , 255 , 19 ) ;
int cnt = tableSize0 + tableSize1 ;
uint8 * tmp = _tables [ 0 ] ;
while ( cnt ) {
uint16 cmd = _src - > getKeyLower ( ) ;
cmd = READ_LE_UINT16 ( & _tables [ 8 ] [ cmd < < 1 ] ) ;
_src - > advSrcBitsByIndex ( _tables [ 7 ] [ cmd ] ) ;
if ( cmd < 16 ) {
* tmp + + = cmd ;
cnt - - ;
} else {
uint8 tmpI = 0 ;
if ( cmd = = 16 ) {
cmd = _src - > getKeyMasked ( 2 ) + 3 ;
tmpI = * ( tmp - 1 ) ;
} else if ( cmd = = 17 ) {
cmd = _src - > getKeyMasked ( 3 ) + 3 ;
} else {
cmd = _src - > getKeyMasked ( 7 ) + 11 ;
}
_src - > setIndex ( tmpI ) ;
memset ( tmp , tmpI , cmd ) ;
tmp + = cmd ;
cnt - = cmd ;
if ( cnt < 0 )
error ( " decompression failure " ) ;
}
}
memcpy ( _tables [ 1 ] , _tables [ 0 ] + tableSize0 , tableSize1 ) ;
generateTables ( 0 , 2 , 3 , tableSize0 ) ;
generateTables ( 1 , 4 , 5 , tableSize1 ) ;
postprocess = true ;
} else if ( mode < 0 ) {
_src - > copyBytes ( d ) ;
postprocess = false ;
needrefresh = true ;
} else if ( mode = = 0 ) {
2008-05-24 17:34:20 +00:00
uint8 * d2 = _tables [ 0 ] ;
2008-05-24 16:30:18 +00:00
memset ( d2 , 8 , 144 ) ;
memset ( d2 + 144 , 9 , 112 ) ;
memset ( d2 + 256 , 7 , 24 ) ;
memset ( d2 + 280 , 8 , 8 ) ;
2008-05-24 17:34:20 +00:00
d2 = _tables [ 1 ] ;
2008-05-24 16:30:18 +00:00
memset ( d2 , 5 , 32 ) ;
tableSize0 = 288 ;
tableSize1 = 32 ;
generateTables ( 0 , 2 , 3 , tableSize0 ) ;
generateTables ( 1 , 4 , 5 , tableSize1 ) ;
postprocess = true ;
} else {
error ( " decompression failure " ) ;
}
if ( ! postprocess )
continue ;
int16 cmd = 0 ;
do {
cmd = ( ( int16 * ) _tables [ 2 ] ) [ _src - > getKeyLower ( ) ] ;
_src - > advSrcBitsByIndex ( cmd < 0 ? calcCmdAndIndex ( _tables [ 3 ] , cmd ) : _tables [ 0 ] [ cmd ] ) ;
if ( cmd = = 0x11d ) {
cmd = 0x200 ;
} else if ( cmd > 0x108 ) {
cmd = _src - > keyMaskedAlign ( cmd ) ;
}
if ( ! ( cmd > > 8 ) ) {
* d + + = cmd & 0xff ;
} else if ( cmd ! = 0x100 ) {
cmd - = 0xfe ;
int16 offset = ( ( int16 * ) _tables [ 4 ] ) [ _src - > getKeyLower ( ) ] ;
_src - > advSrcBitsByIndex ( offset < 0 ? calcCmdAndIndex ( _tables [ 5 ] , offset ) : _tables [ 1 ] [ offset ] ) ;
if ( ( offset & 0xff ) > = 4 ) {
uint8 newIndex = ( ( offset & 0xff ) > > 1 ) - 1 ;
2008-06-01 15:11:08 +00:00
offset = ( ( ( offset & 1 ) + 2 ) < < newIndex ) ;
offset + = _src - > getKeyMasked ( newIndex ) ;
2008-05-24 16:30:18 +00:00
}
uint8 * s2 = d - 1 - offset ;
if ( s2 > = dst ) {
while ( cmd - - )
* d + + = * s2 + + ;
} else {
uint32 pos = dst - s2 ;
s2 + = ( d - dst ) ;
if ( pos < ( uint32 ) cmd ) {
cmd - = pos ;
while ( pos - - )
* d + + = * s2 + + ;
2008-05-24 17:34:20 +00:00
s2 = dst ;
2008-05-24 16:30:18 +00:00
}
while ( cmd - - )
* d + + = * s2 + + ;
}
}
} while ( cmd ! = 0x100 ) ;
}
delete _src ;
_src = 0 ;
return true ;
}
void FileExpander : : generateTables ( uint8 srcIndex , uint8 dstIndex , uint8 dstIndex2 , int cnt ) {
const uint8 * tbl1 = _tables [ srcIndex ] ;
2008-07-31 10:47:15 +00:00
uint8 * tbl2 = _tables [ dstIndex ] ;
2008-05-24 16:30:18 +00:00
const uint8 * tbl3 = dstIndex2 = = 0xff ? 0 : _tables [ dstIndex2 ] ;
if ( ! cnt )
return ;
2008-05-24 17:34:20 +00:00
const uint8 * s = tbl1 ;
2008-05-24 16:30:18 +00:00
memset ( _tables16 [ 0 ] , 0 , 32 ) ;
for ( int i = 0 ; i < cnt ; i + + )
_tables16 [ 0 ] [ ( * s + + ) ] + + ;
_tables16 [ 1 ] [ 1 ] = 0 ;
for ( uint16 i = 1 , r = 0 ; i < 16 ; i + + ) {
r = ( r + _tables16 [ 0 ] [ i ] ) < < 1 ;
_tables16 [ 1 ] [ i + 1 ] = r ;
}
if ( _tables16 [ 1 ] [ 16 ] ) {
uint16 r = 0 ;
for ( uint16 i = 1 ; i < 16 ; i + + )
r + = _tables16 [ 0 ] [ i ] ;
if ( r > 1 )
error ( " decompression failure " ) ;
}
2008-05-24 17:34:20 +00:00
s = tbl1 ;
2008-05-24 16:30:18 +00:00
uint16 * d = _tables16 [ 2 ] ;
for ( int i = 0 ; i < cnt ; i + + ) {
uint16 t = * s + + ;
if ( t ) {
_tables16 [ 1 ] [ t ] + + ;
t = _tables16 [ 1 ] [ t ] - 1 ;
}
* d + + = t ;
}
2008-05-24 17:34:20 +00:00
s = tbl1 ;
2008-05-24 16:30:18 +00:00
d = _tables16 [ 2 ] ;
for ( int i = 0 ; i < cnt ; i + + ) {
int8 t = ( ( int8 ) ( * s + + ) ) - 1 ;
if ( t > 0 ) {
uint16 v1 = * d ;
uint16 v2 = 0 ;
do {
v2 = ( v2 < < 1 ) | ( v1 & 1 ) ;
v1 > > = 1 ;
} while ( - - t & & v1 ) ;
t + + ;
uint8 c1 = ( v1 & 1 ) ;
while ( t - - ) {
uint8 c2 = v2 > > 15 ;
v2 = ( v2 < < 1 ) | c1 ;
c1 = c2 ;
} ;
* d + + = v2 ;
} else {
d + + ;
}
}
2008-07-31 10:47:15 +00:00
memset ( tbl2 , 0 , 512 ) ;
2008-05-24 16:30:18 +00:00
cnt - - ;
2008-05-24 17:34:20 +00:00
s = tbl1 + cnt ;
2008-05-24 16:30:18 +00:00
d = & _tables16 [ 2 ] [ cnt ] ;
uint16 * bt = ( uint16 * ) tbl3 ;
uint16 inc = 0 ;
uint16 cnt2 = 0 ;
do {
uint8 t = * s - - ;
uint16 * s2 = ( uint16 * ) tbl2 ;
if ( t & & t < 9 ) {
inc = 1 < < t ;
uint16 o = * d ;
do {
s2 [ o ] = cnt ;
o + = inc ;
} while ( ! ( o & 0xf00 ) ) ;
} else if ( t > 8 ) {
if ( ! bt )
error ( " decompression failure " ) ;
t - = 8 ;
uint8 shiftCnt = 1 ;
uint8 v = ( * d ) > > 8 ;
s2 = & ( ( uint16 * ) tbl2 ) [ * d & 0xff ] ;
do {
if ( ! * s2 ) {
* s2 = ( uint16 ) ( ~ cnt2 ) ;
* ( uint32 * ) & bt [ cnt2 ] = 0 ;
cnt2 + = 2 ;
}
s2 = & bt [ ( uint16 ) ( ~ * s2 ) ] ;
if ( v & shiftCnt )
s2 + + ;
shiftCnt < < = 1 ;
} while ( - - t ) ;
* s2 = cnt ;
}
d - - ;
} while ( - - cnt > = 0 ) ;
}
uint8 FileExpander : : calcCmdAndIndex ( const uint8 * tbl , int16 & para ) {
2008-05-24 17:34:20 +00:00
const uint16 * t = ( const uint16 * ) tbl ;
2008-05-24 16:30:18 +00:00
_src - > advSrcBitsByIndex ( 8 ) ;
uint8 newIndex = 0 ;
uint16 v = _src - > getKeyLower ( ) ;
do {
newIndex + + ;
para = t [ ( ( ~ para ) & 0xfffe ) | ( v & 1 ) ] ;
v > > = 1 ;
} while ( para < 0 ) ;
return newIndex ;
}
2008-05-31 20:48:41 +00:00
class CompLoaderInsHof : public CompArchiveLoader {
2008-05-24 16:30:18 +00:00
public :
2008-08-11 14:47:50 +00:00
CompLoaderInsHof ( ) {
_fileExtP = " %03d " ;
_checkFile1 = " WESTWOOD.001 " ;
_checkFile2 = " WESTWOOD.002 " ;
_containerOffset = 6 ;
}
2008-05-24 16:30:18 +00:00
2008-08-11 14:47:50 +00:00
virtual bool checkForFiles ( ) const ;
virtual bool loadFile ( CompFileMap & loadTo ) const ;
protected :
2008-05-31 20:48:41 +00:00
struct Archive {
Common : : String filename ;
uint32 firstFile ;
uint32 startOffset ;
uint32 lastFile ;
uint32 endOffset ;
uint32 totalSize ;
} ;
2008-08-11 14:47:50 +00:00
const char * _fileExtP ;
const char * _checkFile1 ;
const char * _checkFile2 ;
uint8 _containerOffset ;
} ;
class CompLoaderInsLol : public CompLoaderInsHof {
public :
CompLoaderInsLol ( ) {
_fileExtP = " %d " ;
_checkFile1 = " WESTWOOD.1 " ;
_checkFile2 = " WESTWOOD.2 " ;
_containerOffset = 0 ;
}
2008-05-31 20:48:41 +00:00
} ;
2008-05-24 16:30:18 +00:00
2008-05-31 20:48:41 +00:00
bool CompLoaderInsHof : : checkForFiles ( ) const {
2008-08-11 14:47:50 +00:00
return ( Common : : File : : exists ( _checkFile1 ) & & Common : : File : : exists ( _checkFile2 ) ) ;
2008-05-24 16:30:18 +00:00
}
2008-05-31 20:48:41 +00:00
bool CompLoaderInsHof : : loadFile ( CompFileMap & loadTo ) const {
2008-05-24 16:30:18 +00:00
Common : : File tmpFile ;
uint32 pos = 0 ;
uint32 bytesleft = 0 ;
bool startFile = true ;
2008-05-31 20:48:41 +00:00
Common : : String filenameBase = " WESTWOOD. " ;
2008-05-24 19:18:17 +00:00
Common : : String filenameTemp ;
char filenameExt [ 4 ] ;
2008-05-24 16:30:18 +00:00
2008-05-24 19:18:17 +00:00
while ( filenameBase . lastChar ( ) ! = ' . ' )
filenameBase . deleteLastChar ( ) ;
2008-05-24 16:30:18 +00:00
2008-05-31 20:48:41 +00:00
Archive newArchive ;
2008-05-24 16:30:18 +00:00
2008-05-31 20:48:41 +00:00
Common : : List < Archive > archives ;
2008-05-24 16:30:18 +00:00
2008-05-31 20:48:41 +00:00
for ( int8 currentFile = 1 ; currentFile ; currentFile + + ) {
2008-08-11 14:47:50 +00:00
sprintf ( filenameExt , _fileExtP , currentFile ) ;
2008-05-24 19:18:17 +00:00
filenameTemp = filenameBase + Common : : String ( filenameExt ) ;
2008-05-24 16:30:18 +00:00
2008-05-24 19:18:17 +00:00
if ( ! tmpFile . open ( filenameTemp ) ) {
debug ( 3 , " couldn't open file '%s' \n " , filenameTemp . c_str ( ) ) ;
2008-05-24 16:30:18 +00:00
break ;
}
tmpFile . seek ( pos ) ;
uint8 fileId = tmpFile . readByte ( ) ;
pos + + ;
uint32 size = tmpFile . size ( ) - 1 ;
if ( startFile ) {
size - = 4 ;
if ( fileId = = currentFile ) {
2008-08-11 14:47:50 +00:00
size - = _containerOffset ;
pos + = _containerOffset ;
tmpFile . seek ( _containerOffset , SEEK_CUR ) ;
2008-05-24 16:30:18 +00:00
} else {
2008-05-24 17:34:20 +00:00
size = size + 1 - pos ;
2008-05-24 16:30:18 +00:00
}
2008-05-24 19:18:17 +00:00
newArchive . filename = filenameBase ;
2008-05-24 16:30:18 +00:00
bytesleft = newArchive . totalSize = tmpFile . readUint32LE ( ) ;
pos + = 4 ;
newArchive . firstFile = currentFile ;
newArchive . startOffset = pos ;
startFile = false ;
}
uint32 cs = MIN ( size , bytesleft ) ;
bytesleft - = cs ;
tmpFile . close ( ) ;
pos + = cs ;
if ( cs = = size ) {
if ( ! bytesleft ) {
newArchive . lastFile = currentFile ;
newArchive . endOffset = - - pos ;
archives . push_back ( newArchive ) ;
currentFile = - 1 ;
} else {
pos = 0 ;
}
} else {
startFile = true ;
bytesleft = size - cs ;
newArchive . lastFile = currentFile - - ;
newArchive . endOffset = - - pos ;
archives . push_back ( newArchive ) ;
}
}
2008-05-31 21:48:09 +00:00
FileExpander exp ;
2008-05-31 20:48:41 +00:00
CompFileEntry newEntry ;
uint32 insize = 0 ;
uint32 outsize = 0 ;
uint8 * inbuffer = 0 ;
uint8 * outbuffer = 0 ;
uint32 inPart1 = 0 ;
uint32 inPart2 = 0 ;
2008-08-11 14:47:50 +00:00
uint8 compressionType = 0 ;
2008-05-31 20:48:41 +00:00
Common : : String entryStr ;
2008-05-24 16:30:18 +00:00
pos = 0 ;
const uint32 kExecSize = 0x0bba ;
const uint32 kHeaderSize = 30 ;
const uint32 kHeaderSize2 = 46 ;
2008-05-31 20:48:41 +00:00
for ( Common : : List < Archive > : : iterator a = archives . begin ( ) ; a ! = archives . end ( ) ; + + a ) {
2008-05-24 17:08:35 +00:00
startFile = true ;
2008-05-24 16:30:18 +00:00
for ( uint32 i = a - > firstFile ; i ! = ( a - > lastFile + 1 ) ; i + + ) {
2008-08-11 14:47:50 +00:00
sprintf ( filenameExt , _fileExtP , i ) ;
2008-05-24 19:18:17 +00:00
filenameTemp = a - > filename + Common : : String ( filenameExt ) ;
2008-05-24 16:30:18 +00:00
2008-05-24 19:18:17 +00:00
if ( ! tmpFile . open ( filenameTemp ) ) {
debug ( 3 , " couldn't open file '%s' \n " , filenameTemp . c_str ( ) ) ;
2008-05-24 16:30:18 +00:00
break ;
}
uint32 size = ( i = = a - > lastFile ) ? a - > endOffset : tmpFile . size ( ) ;
if ( startFile ) {
startFile = false ;
pos = a - > startOffset + kExecSize ;
if ( pos > size ) {
pos - = size ;
tmpFile . close ( ) ;
continue ;
}
} else {
2008-05-31 20:48:41 +00:00
if ( inPart2 ) {
tmpFile . seek ( 1 ) ;
tmpFile . read ( inbuffer + inPart1 , inPart2 ) ;
inPart2 = 0 ;
2008-08-11 14:47:50 +00:00
if ( compressionType > 0 )
exp . process ( outbuffer , inbuffer , outsize , insize ) ;
else
memcpy ( outbuffer , inbuffer , outsize ) ;
2008-05-31 20:48:41 +00:00
delete [ ] inbuffer ;
inbuffer = 0 ;
newEntry . data = outbuffer ;
newEntry . size = outsize ;
loadTo [ entryStr ] = newEntry ;
}
pos + + ;
2008-05-24 16:30:18 +00:00
}
while ( pos < size ) {
uint8 hdr [ 43 ] ;
uint32 m = 0 ;
tmpFile . seek ( pos ) ;
if ( pos + 42 > size ) {
m = size - pos ;
uint32 b = 42 - m ;
if ( m > = 4 ) {
uint32 id = tmpFile . readUint32LE ( ) ;
if ( id = = 0x06054B50 ) {
startFile = true ;
break ;
} else {
tmpFile . seek ( pos ) ;
}
}
2008-05-24 19:18:17 +00:00
2008-08-11 14:47:50 +00:00
sprintf ( filenameExt , _fileExtP , i + 1 ) ;
2008-05-24 19:18:17 +00:00
filenameTemp = a - > filename + Common : : String ( filenameExt ) ;
2008-05-24 16:30:18 +00:00
Common : : File tmpFile2 ;
2008-05-24 19:18:17 +00:00
tmpFile2 . open ( filenameTemp ) ;
2008-05-24 16:30:18 +00:00
tmpFile . read ( hdr , m ) ;
tmpFile2 . read ( hdr + m , b ) ;
tmpFile2 . close ( ) ;
} else {
tmpFile . read ( hdr , 42 ) ;
}
uint32 id = READ_LE_UINT32 ( hdr ) ;
if ( id = = 0x04034B50 ) {
2008-08-11 14:47:50 +00:00
compressionType = hdr [ 8 ] ;
2008-05-31 20:48:41 +00:00
insize = READ_LE_UINT32 ( hdr + 18 ) ;
outsize = READ_LE_UINT32 ( hdr + 22 ) ;
2008-05-24 16:30:18 +00:00
uint16 filestrlen = READ_LE_UINT16 ( hdr + 26 ) ;
* ( hdr + 30 + filestrlen ) = 0 ;
2008-05-31 20:48:41 +00:00
entryStr = Common : : String ( ( const char * ) ( hdr + 30 ) ) ;
2008-05-24 16:30:18 +00:00
pos + = ( kHeaderSize + filestrlen - m ) ;
2008-05-31 20:48:41 +00:00
tmpFile . seek ( pos ) ;
2008-05-24 16:30:18 +00:00
2008-05-31 20:48:41 +00:00
outbuffer = new uint8 [ outsize ] ;
2008-05-31 23:26:41 +00:00
if ( ! outbuffer )
error ( " Out of memory: Can't uncompress installer files " ) ;
2008-05-31 20:48:41 +00:00
if ( ! inbuffer ) {
inbuffer = new uint8 [ insize ] ;
2008-05-31 23:26:41 +00:00
if ( ! inbuffer )
error ( " Out of memory: Can't uncompress installer files " ) ;
2008-05-31 20:48:41 +00:00
}
if ( ( pos + insize ) > size ) {
// this is for files that are split between two archive files
inPart1 = size - pos ;
inPart2 = insize - inPart1 ;
tmpFile . read ( inbuffer , inPart1 ) ;
} else {
tmpFile . read ( inbuffer , insize ) ;
inPart2 = 0 ;
2008-08-11 14:47:50 +00:00
if ( compressionType > 0 )
exp . process ( outbuffer , inbuffer , outsize , insize ) ;
else
memcpy ( outbuffer , inbuffer , outsize ) ;
2008-05-31 20:48:41 +00:00
delete [ ] inbuffer ;
inbuffer = 0 ;
newEntry . data = outbuffer ;
newEntry . size = outsize ;
loadTo [ entryStr ] = newEntry ;
}
2008-05-24 16:30:18 +00:00
2008-05-31 20:48:41 +00:00
pos + = insize ;
2008-05-24 16:30:18 +00:00
if ( pos > size ) {
pos - = size ;
break ;
}
} else {
uint32 filestrlen = READ_LE_UINT32 ( hdr + 28 ) ;
pos + = ( kHeaderSize2 + filestrlen - m ) ;
}
}
tmpFile . close ( ) ;
}
}
2008-05-31 20:48:41 +00:00
archives . clear ( ) ;
2008-05-24 16:30:18 +00:00
return true ;
2008-02-09 15:18:35 +00:00
}
2008-04-17 16:38:26 +00:00
# pragma mark -
2008-02-07 23:13:13 +00:00
void Resource : : initializeLoaders ( ) {
2008-03-28 06:03:59 +00:00
_loaders . push_back ( LoaderList : : value_type ( new ResLoaderPak ( ) ) ) ;
2008-05-24 16:30:18 +00:00
_loaders . push_back ( LoaderList : : value_type ( new ResLoaderInsMalcolm ( ) ) ) ;
2008-04-17 16:38:26 +00:00
_loaders . push_back ( LoaderList : : value_type ( new ResLoaderTlk ( ) ) ) ;
2008-05-31 20:48:41 +00:00
_compLoaders . push_back ( CompLoaderList : : value_type ( new CompLoaderInsHof ( ) ) ) ;
2008-08-11 14:47:50 +00:00
_compLoaders . push_back ( CompLoaderList : : value_type ( new CompLoaderInsLol ( ) ) ) ;
2006-07-08 13:56:56 +00:00
}
2008-02-07 23:13:13 +00:00
const ResArchiveLoader * Resource : : getLoader ( ResFileEntry : : kType type ) const {
for ( CLoaderIterator i = _loaders . begin ( ) ; i ! = _loaders . end ( ) ; + + i ) {
if ( ( * i ) - > getType ( ) = = type )
2008-03-28 06:03:59 +00:00
return ( * i ) . get ( ) ;
2008-02-07 23:13:13 +00:00
}
return 0 ;
2006-07-08 13:56:56 +00:00
}
2004-10-15 06:06:47 +00:00
} // end of namespace Kyra
2007-04-15 16:41:20 +00:00
2008-03-28 06:03:59 +00:00
2008-05-31 20:48:41 +00:00