2003-12-16 02:10:15 +00:00
/* ScummVM - Scumm Interpreter
2006-01-18 17:39:49 +00:00
* Copyright ( C ) 2003 - 2006 The ScummVM project
2003-12-16 02:10:15 +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 .
2003-12-16 02:10:15 +00:00
*
2006-02-11 10:01:01 +00:00
* $ URL $
* $ Id $
2003-12-16 02:10:15 +00:00
*
*/
2005-06-24 15:23:51 +00:00
# include "common/stdafx.h"
2006-03-29 15:59:37 +00:00
# include "common/endian.h"
2004-07-11 04:41:48 +00:00
# include "common/config-manager.h"
2003-12-16 02:10:15 +00:00
# include "common/util.h"
2004-07-11 04:41:48 +00:00
# include "common/str.h"
2006-03-29 15:59:37 +00:00
# include "base/engine.h"
# include "sword1/memman.h"
# include "sword1/resman.h"
# include "sword1/sworddefs.h"
2004-10-21 12:37:13 +00:00
# include "sword1/swordres.h"
2003-12-16 02:10:15 +00:00
2004-07-11 04:41:48 +00:00
# include "gui/message.h"
# include "gui/newgui.h"
2004-01-11 15:47:41 +00:00
namespace Sword1 {
2004-07-11 04:41:48 +00:00
void guiFatalError ( char * msg ) {
// Displays a dialog on-screen before terminating the engine.
// TODO: We really need to setup a special palette for cases when
// the engine is erroring before setting one... otherwise invisible cursor :)
GUI : : MessageDialog dialog ( msg ) ;
dialog . runModal ( ) ;
error ( msg ) ;
}
2004-01-11 15:47:41 +00:00
2003-12-16 02:10:15 +00:00
# define MAX_PATH_LEN 260
2005-02-21 08:15:15 +00:00
ResMan : : ResMan ( const char * fileName ) {
2005-02-20 18:53:30 +00:00
_openCluStart = _openCluEnd = NULL ;
_openClus = 0 ;
2004-11-19 07:55:33 +00:00
_memMan = new MemMan ( ) ;
2005-02-21 08:15:15 +00:00
loadCluDescript ( fileName ) ;
2003-12-16 02:10:15 +00:00
}
ResMan : : ~ ResMan ( void ) {
2004-11-09 04:06:10 +00:00
#if 0
for ( uint32 clusCnt = 0 ; clusCnt < _prj . noClu ; clusCnt + + ) {
Clu * cluster = _prj . clu [ clusCnt ] ;
if ( cluster ) {
for ( uint32 grpCnt = 0 ; grpCnt < cluster - > noGrp ; grpCnt + + ) {
Grp * group = cluster - > grp [ grpCnt ] ;
if ( group ) {
for ( uint32 resCnt = 0 ; resCnt < group - > noRes ; resCnt + + ) {
if ( group - > resHandle [ resCnt ] . cond = = MEM_DONT_FREE ) {
warning ( " ResMan::~ResMan: Resource %02X.%04X.%02X is still open " ,
clusCnt + 1 , grpCnt , resCnt ) ;
}
}
}
}
}
}
debug ( 0 , " ResMan closed \n " ) ;
# endif
2004-11-19 07:55:33 +00:00
flush ( ) ;
2003-12-16 02:10:15 +00:00
freeCluDescript ( ) ;
2004-11-19 07:55:33 +00:00
delete _memMan ;
2003-12-16 02:10:15 +00:00
}
void ResMan : : loadCluDescript ( const char * fileName ) {
2005-05-10 22:56:25 +00:00
Common : : File file ;
2005-02-21 08:15:15 +00:00
file . open ( fileName ) ;
2004-07-11 04:41:48 +00:00
2005-02-21 08:15:15 +00:00
if ( ! file . isOpen ( ) ) {
2004-07-11 04:41:48 +00:00
char msg [ 512 ] ;
sprintf ( msg , " Couldn't open CLU description '%s' \n \n If you are running from CD, please ensure you have read the ScummVM documentation regarding multi-cd games. " , fileName ) ;
guiFatalError ( msg ) ;
}
2005-07-30 21:11:48 +00:00
2005-02-21 08:15:15 +00:00
_prj . noClu = file . readUint32LE ( ) ;
2005-02-20 18:53:30 +00:00
_prj . clu = new Clu [ _prj . noClu ] ;
memset ( _prj . clu , 0 , _prj . noClu * sizeof ( Clu ) ) ;
2003-12-16 02:10:15 +00:00
uint32 * cluIndex = ( uint32 * ) malloc ( _prj . noClu * 4 ) ;
2005-02-21 08:15:15 +00:00
file . read ( cluIndex , _prj . noClu * 4 ) ;
2003-12-16 02:10:15 +00:00
for ( uint32 clusCnt = 0 ; clusCnt < _prj . noClu ; clusCnt + + )
if ( cluIndex [ clusCnt ] ) {
2005-02-20 18:53:30 +00:00
Clu * cluster = _prj . clu + clusCnt ;
2005-02-21 08:15:15 +00:00
file . read ( cluster - > label , MAX_LABEL_SIZE ) ;
2003-12-16 02:10:15 +00:00
2005-02-20 18:53:30 +00:00
cluster - > file = NULL ;
2005-02-21 08:15:15 +00:00
cluster - > noGrp = file . readUint32LE ( ) ;
2005-02-20 18:53:30 +00:00
cluster - > grp = new Grp [ cluster - > noGrp ] ;
2005-04-27 02:16:34 +00:00
cluster - > nextOpen = NULL ;
2005-02-20 18:53:30 +00:00
memset ( cluster - > grp , 0 , cluster - > noGrp * sizeof ( Grp ) ) ;
cluster - > refCount = 0 ;
2003-12-16 02:10:15 +00:00
uint32 * grpIndex = ( uint32 * ) malloc ( cluster - > noGrp * 4 ) ;
2005-02-21 08:15:15 +00:00
file . read ( grpIndex , cluster - > noGrp * 4 ) ;
2003-12-16 02:10:15 +00:00
for ( uint32 grpCnt = 0 ; grpCnt < cluster - > noGrp ; grpCnt + + )
if ( grpIndex [ grpCnt ] ) {
2005-02-20 18:53:30 +00:00
Grp * group = cluster - > grp + grpCnt ;
2005-02-21 08:15:15 +00:00
group - > noRes = file . readUint32LE ( ) ;
2004-01-11 15:47:41 +00:00
group - > resHandle = new MemHandle [ group - > noRes ] ;
2003-12-16 02:10:15 +00:00
group - > offset = new uint32 [ group - > noRes ] ;
group - > length = new uint32 [ group - > noRes ] ;
uint32 * resIdIdx = ( uint32 * ) malloc ( group - > noRes * 4 ) ;
2005-02-21 08:15:15 +00:00
file . read ( resIdIdx , group - > noRes * 4 ) ;
2003-12-16 02:10:15 +00:00
for ( uint32 resCnt = 0 ; resCnt < group - > noRes ; resCnt + + ) {
if ( resIdIdx [ resCnt ] ) {
2005-02-21 08:15:15 +00:00
group - > offset [ resCnt ] = file . readUint32LE ( ) ;
group - > length [ resCnt ] = file . readUint32LE ( ) ;
2003-12-16 02:10:15 +00:00
_memMan - > initHandle ( group - > resHandle + resCnt ) ;
} else {
group - > offset [ resCnt ] = 0xFFFFFFFF ;
group - > length [ resCnt ] = 0 ;
_memMan - > initHandle ( group - > resHandle + resCnt ) ;
}
}
2003-12-19 14:07:12 +00:00
free ( resIdIdx ) ;
2005-02-20 18:53:30 +00:00
}
2003-12-16 02:10:15 +00:00
free ( grpIndex ) ;
2005-02-20 18:53:30 +00:00
}
2003-12-16 02:10:15 +00:00
free ( cluIndex ) ;
2005-07-30 21:11:48 +00:00
2005-02-20 18:53:30 +00:00
if ( _prj . clu [ 3 ] . grp [ 5 ] . noRes = = 29 )
2003-12-28 19:03:35 +00:00
for ( uint8 cnt = 0 ; cnt < 29 ; cnt + + )
2003-12-20 16:30:58 +00:00
_srIdList [ cnt ] = 0x04050000 | cnt ;
2003-12-16 02:10:15 +00:00
}
void ResMan : : freeCluDescript ( void ) {
2005-07-30 21:11:48 +00:00
2005-02-20 18:53:30 +00:00
for ( uint32 clusCnt = 0 ; clusCnt < _prj . noClu ; clusCnt + + ) {
Clu * cluster = _prj . clu + clusCnt ;
for ( uint32 grpCnt = 0 ; grpCnt < cluster - > noGrp ; grpCnt + + ) {
Grp * group = cluster - > grp + grpCnt ;
if ( group - > resHandle ! = NULL ) {
for ( uint32 resCnt = 0 ; resCnt < group - > noRes ; resCnt + + )
_memMan - > freeNow ( group - > resHandle + resCnt ) ;
delete [ ] group - > resHandle ;
delete [ ] group - > offset ;
delete [ ] group - > length ;
}
2003-12-16 02:10:15 +00:00
}
2005-02-20 18:53:30 +00:00
delete [ ] cluster - > grp ;
if ( cluster - > file ! = NULL )
delete cluster - > file ;
}
2003-12-16 02:10:15 +00:00
delete [ ] _prj . clu ;
}
2003-12-20 09:12:54 +00:00
void ResMan : : flush ( void ) {
2005-02-20 18:53:30 +00:00
for ( uint32 clusCnt = 0 ; clusCnt < _prj . noClu ; clusCnt + + ) {
Clu * cluster = _prj . clu + clusCnt ;
for ( uint32 grpCnt = 0 ; grpCnt < cluster - > noGrp ; grpCnt + + ) {
Grp * group = cluster - > grp + grpCnt ;
for ( uint32 resCnt = 0 ; resCnt < group - > noRes ; resCnt + + )
if ( group - > resHandle [ resCnt ] . cond ! = MEM_FREED ) {
_memMan - > setCondition ( group - > resHandle + resCnt , MEM_CAN_FREE ) ;
group - > resHandle [ resCnt ] . refCount = 0 ;
}
}
if ( cluster - > file ) {
cluster - > file - > close ( ) ;
delete cluster - > file ;
cluster - > file = NULL ;
cluster - > refCount = 0 ;
}
}
_openClus = 0 ;
_openCluStart = _openCluEnd = NULL ;
2004-11-19 07:55:33 +00:00
// the memory manager cached the blocks we asked it to free, so explicitly make it free them
_memMan - > flush ( ) ;
2003-12-20 09:12:54 +00:00
}
2003-12-16 02:10:15 +00:00
void * ResMan : : fetchRes ( uint32 id ) {
2004-01-11 15:47:41 +00:00
MemHandle * memHandle = resHandle ( id ) ;
2003-12-16 02:10:15 +00:00
if ( ! memHandle - > data )
error ( " fetchRes:: resource %d is not open! " , id ) ;
return memHandle - > data ;
}
void * ResMan : : openFetchRes ( uint32 id ) {
resOpen ( id ) ;
return fetchRes ( id ) ;
}
void ResMan : : dumpRes ( uint32 id ) {
char outn [ 30 ] ;
sprintf ( outn , " DUMP%08X.BIN " , id ) ;
2005-05-10 22:56:25 +00:00
Common : : File outf ;
if ( outf . open ( outn , Common : : File : : kFileWriteMode ) ) {
2004-01-11 16:27:36 +00:00
resOpen ( id ) ;
MemHandle * memHandle = resHandle ( id ) ;
outf . write ( memHandle - > data , memHandle - > size ) ;
outf . close ( ) ;
resClose ( id ) ;
}
2003-12-16 02:10:15 +00:00
}
Header * ResMan : : lockScript ( uint32 scrID ) {
if ( ! _scriptList [ scrID / ITM_PER_SEC ] )
error ( " Script id %d not found. \n " , scrID ) ;
scrID = _scriptList [ scrID / ITM_PER_SEC ] ;
# ifdef SCUMM_BIG_ENDIAN
2004-01-11 15:47:41 +00:00
MemHandle * memHandle = resHandle ( scrID ) ;
2003-12-16 02:10:15 +00:00
if ( memHandle - > cond = = MEM_FREED )
openScriptResourceBigEndian ( scrID ) ;
else
resOpen ( scrID ) ;
# else
resOpen ( scrID ) ;
# endif
return ( Header * ) resHandle ( scrID ) - > data ;
}
void ResMan : : unlockScript ( uint32 scrID ) {
resClose ( _scriptList [ scrID / ITM_PER_SEC ] ) ;
}
void * ResMan : : cptResOpen ( uint32 id ) {
# ifdef SCUMM_BIG_ENDIAN
2004-01-11 15:47:41 +00:00
MemHandle * memHandle = resHandle ( id ) ;
2003-12-16 02:10:15 +00:00
if ( memHandle - > cond = = MEM_FREED )
openCptResourceBigEndian ( id ) ;
else
resOpen ( id ) ;
# else
resOpen ( id ) ;
# endif
return resHandle ( id ) - > data ;
}
void ResMan : : resOpen ( uint32 id ) { // load resource ID into memory
2004-01-11 15:47:41 +00:00
MemHandle * memHandle = resHandle ( id ) ;
2003-12-16 02:10:15 +00:00
if ( memHandle - > cond = = MEM_FREED ) { // memory has been freed
uint32 size = resLength ( id ) ;
_memMan - > alloc ( memHandle , size ) ;
2005-05-10 22:56:25 +00:00
Common : : File * clusFile = resFile ( id ) ;
2005-02-20 18:53:30 +00:00
assert ( clusFile ) ;
2003-12-16 02:10:15 +00:00
clusFile - > seek ( resOffset ( id ) ) ;
clusFile - > read ( memHandle - > data , size ) ;
2005-10-26 05:33:23 +00:00
if ( clusFile - > ioFailed ( ) ) {
error ( " Can't read %d bytes from offset %d from cluster file %s \n Resource ID: %d (%08X) \n " , size , resOffset ( id ) , _prj . clu [ ( id > > 24 ) - 1 ] . label , id , id ) ;
}
2003-12-16 02:10:15 +00:00
} else
_memMan - > setCondition ( memHandle , MEM_DONT_FREE ) ;
2005-02-20 18:53:30 +00:00
2003-12-16 02:10:15 +00:00
memHandle - > refCount + + ;
if ( memHandle - > refCount > 20 ) {
debug ( 1 , " %d references to id %d. Guess there's something wrong. " , memHandle - > refCount , id ) ;
}
}
void ResMan : : resClose ( uint32 id ) {
2004-01-11 15:47:41 +00:00
MemHandle * handle = resHandle ( id ) ;
2003-12-16 02:10:15 +00:00
if ( ! handle - > refCount ) {
2005-07-30 21:11:48 +00:00
warning ( " Resource Manager fail: unlocking object with refCount 0. Id: %d \n " , id ) ;
2003-12-20 09:12:54 +00:00
} else {
2003-12-16 02:10:15 +00:00
handle - > refCount - - ;
2003-12-20 09:12:54 +00:00
if ( ! handle - > refCount )
_memMan - > setCondition ( handle , MEM_CAN_FREE ) ;
}
2003-12-16 02:10:15 +00:00
}
FrameHeader * ResMan : : fetchFrame ( void * resourceData , uint32 frameNo ) {
uint8 * frameFile = ( uint8 * ) resourceData ;
2003-12-19 14:07:12 +00:00
uint8 * idxData = frameFile + sizeof ( Header ) ;
2003-12-16 02:10:15 +00:00
if ( frameNo > = READ_LE_UINT32 ( idxData ) )
error ( " fetchFrame:: frame %d doesn't exist in resource. " , frameNo ) ;
frameFile + = READ_LE_UINT32 ( idxData + ( frameNo + 1 ) * 4 ) ;
return ( FrameHeader * ) frameFile ;
}
2005-05-10 22:56:25 +00:00
Common : : File * ResMan : : resFile ( uint32 id ) {
2005-02-20 18:53:30 +00:00
Clu * cluster = _prj . clu + ( ( id > > 24 ) - 1 ) ;
if ( cluster - > file = = NULL ) {
_openClus + + ;
if ( _openCluEnd = = NULL ) {
_openCluStart = _openCluEnd = cluster ;
} else {
_openCluEnd - > nextOpen = cluster ;
_openCluEnd = cluster ;
}
2005-05-10 22:56:25 +00:00
cluster - > file = new Common : : File ( ) ;
2005-02-20 18:53:30 +00:00
char fileName [ 15 ] ;
sprintf ( fileName , " %s.CLU " , _prj . clu [ ( id > > 24 ) - 1 ] . label ) ;
cluster - > file - > open ( fileName ) ;
if ( ! cluster - > file - > isOpen ( ) ) {
char msg [ 512 ] ;
sprintf ( msg , " Couldn't open game cluster file '%s' \n \n If you are running from CD, please ensure you have read the ScummVM documentation regarding multi-cd games. " , fileName ) ;
guiFatalError ( msg ) ;
}
while ( _openClus > MAX_OPEN_CLUS ) {
assert ( _openCluStart ) ;
Clu * closeClu = _openCluStart ;
_openCluStart = _openCluStart - > nextOpen ;
2005-07-30 21:11:48 +00:00
2005-02-20 18:53:30 +00:00
closeClu - > file - > close ( ) ;
delete closeClu - > file ;
closeClu - > file = NULL ;
closeClu - > nextOpen = NULL ;
2005-04-27 02:16:34 +00:00
_openClus - - ;
2005-02-20 18:53:30 +00:00
}
2004-07-11 04:41:48 +00:00
}
2005-02-20 18:53:30 +00:00
return cluster - > file ;
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
MemHandle * ResMan : : resHandle ( uint32 id ) {
2003-12-20 16:30:58 +00:00
if ( ( id > > 16 ) = = 0x0405 )
id = _srIdList [ id & 0xFFFF ] ;
2003-12-29 15:54:06 +00:00
uint8 cluster = ( uint8 ) ( ( id > > 24 ) - 1 ) ;
uint8 group = ( uint8 ) ( id > > 16 ) ;
2003-12-16 02:10:15 +00:00
2005-02-20 18:53:30 +00:00
return & ( _prj . clu [ cluster ] . grp [ group ] . resHandle [ id & 0xFFFF ] ) ;
2003-12-16 02:10:15 +00:00
}
uint32 ResMan : : resLength ( uint32 id ) {
2003-12-20 16:30:58 +00:00
if ( ( id > > 16 ) = = 0x0405 )
id = _srIdList [ id & 0xFFFF ] ;
2003-12-29 15:54:06 +00:00
uint8 cluster = ( uint8 ) ( ( id > > 24 ) - 1 ) ;
uint8 group = ( uint8 ) ( id > > 16 ) ;
2003-12-16 02:10:15 +00:00
2005-02-20 18:53:30 +00:00
return _prj . clu [ cluster ] . grp [ group ] . length [ id & 0xFFFF ] ;
2003-12-16 02:10:15 +00:00
}
uint32 ResMan : : resOffset ( uint32 id ) {
2003-12-20 16:30:58 +00:00
if ( ( id > > 16 ) = = 0x0405 )
id = _srIdList [ id & 0xFFFF ] ;
2003-12-29 15:54:06 +00:00
uint8 cluster = ( uint8 ) ( ( id > > 24 ) - 1 ) ;
uint8 group = ( uint8 ) ( id > > 16 ) ;
2003-12-16 02:10:15 +00:00
2005-02-20 18:53:30 +00:00
return _prj . clu [ cluster ] . grp [ group ] . offset [ id & 0xFFFF ] ;
2003-12-16 02:10:15 +00:00
}
void ResMan : : openCptResourceBigEndian ( uint32 id ) {
resOpen ( id ) ;
2004-01-11 15:47:41 +00:00
MemHandle * handle = resHandle ( id ) ;
2003-12-16 02:10:15 +00:00
uint32 totSize = handle - > size ;
2003-12-18 01:15:15 +00:00
uint32 * data = ( uint32 * ) ( ( uint8 * ) handle - > data + sizeof ( Header ) ) ;
2003-12-16 02:10:15 +00:00
totSize - = sizeof ( Header ) ;
2003-12-18 01:15:15 +00:00
if ( totSize & 3 )
error ( " Illegal compact size for id %d: %d " , id , totSize ) ;
totSize / = 4 ;
for ( uint32 cnt = 0 ; cnt < totSize ; cnt + + ) {
* data = READ_LE_UINT32 ( data ) ;
data + + ;
2003-12-16 02:10:15 +00:00
}
}
void ResMan : : openScriptResourceBigEndian ( uint32 id ) {
resOpen ( id ) ;
2004-01-11 15:47:41 +00:00
MemHandle * handle = resHandle ( id ) ;
2003-12-16 09:43:08 +00:00
// uint32 totSize = handle->size;
2003-12-16 02:10:15 +00:00
Header * head = ( Header * ) handle - > data ;
2004-10-21 13:23:52 +00:00
head - > comp_length = FROM_LE_32 ( head - > comp_length ) ;
head - > decomp_length = FROM_LE_32 ( head - > decomp_length ) ;
head - > version = FROM_LE_16 ( head - > version ) ;
2003-12-16 02:10:15 +00:00
uint32 * data = ( uint32 * ) ( ( uint8 * ) handle - > data + sizeof ( Header ) ) ;
uint32 size = handle - > size - sizeof ( Header ) ;
if ( size & 3 )
error ( " Odd size during script endian conversion. Resource ID =%d, size = %d " , id , size ) ;
size > > = 2 ;
for ( uint32 cnt = 0 ; cnt < size ; cnt + + ) {
* data = READ_LE_UINT32 ( data ) ;
data + + ;
}
}
2003-12-20 16:30:58 +00:00
uint32 ResMan : : _srIdList [ 29 ] = { // the file numbers differ for the control panel file IDs, so we need this array
2003-12-29 16:08:05 +00:00
OTHER_SR_FONT , // SR_FONT
0x04050000 , // SR_BUTTON
OTHER_SR_REDFONT , // SR_REDFONT
0x04050001 , // SR_PALETTE
0x04050002 , // SR_PANEL_ENGLISH
0x04050003 , // SR_PANEL_FRENCH
0x04050004 , // SR_PANEL_GERMAN
0x04050005 , // SR_PANEL_ITALIAN
0x04050006 , // SR_PANEL_SPANISH
0x04050007 , // SR_PANEL_AMERICAN
0x04050008 , // SR_TEXT_BUTTON
0x04050009 , // SR_SPEED
0x0405000A , // SR_SCROLL1
0x0405000B , // SR_SCROLL2
0x0405000C , // SR_CONFIRM
0x0405000D , // SR_VOLUME
0x0405000E , // SR_VLIGHT
0x0405000F , // SR_VKNOB
0x04050010 , // SR_WINDOW
0x04050011 , // SR_SLAB1
0x04050012 , // SR_SLAB2
0x04050013 , // SR_SLAB3
0x04050014 , // SR_SLAB4
0x04050015 , // SR_BUTUF
0x04050016 , // SR_BUTUS
0x04050017 , // SR_BUTDS
0x04050018 , // SR_BUTDF
0x04050019 , // SR_DEATHPANEL
2003-12-20 16:30:58 +00:00
0 ,
} ;
2004-01-11 15:47:41 +00:00
} // End of namespace Sword1