@ -2235,10 +2235,10 @@ static void SaveSettings(const SettingDesc *sd, void *object)
*
* The PATX chunk contents has the following format :
*
* uint32 chunk flags
* uint32 chunk flags ( unused )
* uint32 number of settings
* For each of N settings :
* uint32 setting flags
* uint32 setting flags ( unused )
* SLE_STR setting name
* uint32 length of setting field
* N bytes setting field
@ -2269,6 +2269,7 @@ static void MakeSettingsPatxList(const SettingDesc *sd)
static const SettingDesc * previous = NULL ;
if ( sd = = previous ) return ;
previous = sd ;
_sorted_patx_settings . clear ( ) ;
for ( const SettingDesc * desc = sd ; desc - > save . cmd ! = SL_END ; desc + + ) {
@ -2279,16 +2280,6 @@ static void MakeSettingsPatxList(const SettingDesc *sd)
std : : sort ( _sorted_patx_settings . begin ( ) , _sorted_patx_settings . end ( ) , StringSorter ( ) ) ;
}
/**
* Internal structure used in LoadSettingsPatx ( )
* placed outside for legacy compiler compatibility
*/
struct SettingsPatxLoad {
uint32 flags ;
char name [ 256 ] ;
uint32 setting_length ;
} ;
/**
* Internal structure used in LoadSettingsPatx ( )
* placed outside for legacy compiler compatibility
@ -2308,6 +2299,38 @@ struct StringSearcher {
}
} ;
/**
* Internal structure used in LoadSettingsPatx ( ) and LoadSettingsPlyx ( )
*/
struct SettingsExtLoad {
uint32 flags ;
char name [ 256 ] ;
uint32 setting_length ;
} ;
static const SaveLoad _settings_ext_load_desc [ ] = {
SLE_VAR ( SettingsExtLoad , flags , SLE_UINT32 ) ,
SLE_STR ( SettingsExtLoad , name , SLE_STRB , 256 ) ,
SLE_VAR ( SettingsExtLoad , setting_length , SLE_UINT32 ) ,
SLE_END ( )
} ;
/**
* Internal structure used in SaveSettingsPatx ( ) and SaveSettingsPlyx ( )
*/
struct SettingsExtSave {
uint32 flags ;
const char * name ;
uint32 setting_length ;
} ;
static const SaveLoad _settings_ext_save_desc [ ] = {
SLE_VAR ( SettingsExtSave , flags , SLE_UINT32 ) ,
SLE_STR ( SettingsExtSave , name , SLE_STR , 0 ) ,
SLE_VAR ( SettingsExtSave , setting_length , SLE_UINT32 ) ,
SLE_END ( )
} ;
/**
* Load handler for settings which go in the PATX chunk
* @ param osd SettingDesc struct containing all information
@ -2318,14 +2341,7 @@ static void LoadSettingsPatx(const SettingDesc *sd, void *object)
{
MakeSettingsPatxList ( sd ) ;
SettingsPatxLoad current_setting ;
static const SaveLoad _settings_patx_desc [ ] = {
SLE_VAR ( SettingsPatxLoad , flags , SLE_UINT32 ) ,
SLE_STR ( SettingsPatxLoad , name , SLE_STRB , 256 ) ,
SLE_VAR ( SettingsPatxLoad , setting_length , SLE_UINT32 ) ,
SLE_END ( )
} ;
SettingsExtLoad current_setting ;
uint32 flags = SlReadUint32 ( ) ;
// flags are not in use yet, reserve for future expansion
@ -2333,7 +2349,7 @@ static void LoadSettingsPatx(const SettingDesc *sd, void *object)
uint32 settings_count = SlReadUint32 ( ) ;
for ( uint32 i = 0 ; i < settings_count ; i + + ) {
SlObject ( & current_setting , _settings_ patx _desc) ;
SlObject ( & current_setting , _settings_ ext_load _desc) ;
// flags are not in use yet, reserve for future expansion
if ( current_setting . flags ! = 0 ) SlErrorCorruptFmt ( " PATX chunk: unknown setting header flags: 0x%X " , current_setting . flags ) ;
@ -2377,19 +2393,7 @@ struct SettingToAdd {
*/
static void SaveSettingsPatx ( const SettingDesc * sd , void * object )
{
struct SettingsPatxSave {
uint32 flags ;
const char * name ;
uint32 setting_length ;
} ;
SettingsPatxSave current_setting ;
static const SaveLoad _settings_patx_desc [ ] = {
SLE_VAR ( SettingsPatxSave , flags , SLE_UINT32 ) ,
SLE_STR ( SettingsPatxSave , name , SLE_STR , 0 ) ,
SLE_VAR ( SettingsPatxSave , setting_length , SLE_UINT32 ) ,
SLE_END ( )
} ;
SettingsExtSave current_setting ;
std : : vector < SettingToAdd > settings_to_add ;
@ -2402,7 +2406,7 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object)
current_setting . name = desc - > patx_name ;
// add length of setting header
length + = SlCalcObjLength ( & current_setting , _settings_ patx _desc) ;
length + = SlCalcObjLength ( & current_setting , _settings_ ext_save _desc) ;
// add length of actual setting
length + = setting_length ;
@ -2421,12 +2425,171 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object)
current_setting . flags = 0 ;
current_setting . name = desc - > patx_name ;
current_setting . setting_length = settings_to_add [ i ] . setting_length ;
SlObject ( & current_setting , _settings_ patx _desc) ;
SlObject ( & current_setting , _settings_ ext_save _desc) ;
void * ptr = GetVariableAddress ( object , & desc - > save ) ;
SlObjectMember ( ptr , & desc - > save ) ;
}
}
/** @file
*
* The PLYX chunk stores additional company settings in an unordered
* format which is tolerant of extra , missing or reordered settings .
* The format is similar to the PATX chunk .
* Additional settings generally means those that aren ' t in trunk .
*
* The PLYX chunk contents has the following format :
*
* uint32 chunk flags ( unused )
* uint32 number of companies
* For each of N companies :
* uint32 company ID
* uint32 company flags ( unused )
* uint32 number of settings
* For each of N settings :
* uint32 setting flags ( unused )
* SLE_STR setting name
* uint32 length of setting field
* N bytes setting field
*/
/**
* Load handler for company settings which go in the PLYX chunk
* @ param check_mode Whether to skip over settings without reading
*/
void LoadSettingsPlyx ( bool skip )
{
SettingsExtLoad current_setting ;
uint32 chunk_flags = SlReadUint32 ( ) ;
// flags are not in use yet, reserve for future expansion
if ( chunk_flags ! = 0 ) SlErrorCorruptFmt ( " PLYX chunk: unknown chunk header flags: 0x%X " , chunk_flags ) ;
uint32 company_count = SlReadUint32 ( ) ;
for ( uint32 i = 0 ; i < company_count ; i + + ) {
uint32 company_id = SlReadUint32 ( ) ;
if ( company_id > = MAX_COMPANIES ) SlErrorCorruptFmt ( " PLYX chunk: invalid company ID: %u " , company_id ) ;
const Company * c = NULL ;
if ( ! skip ) {
c = Company : : GetIfValid ( company_id ) ;
if ( c = = NULL ) SlErrorCorruptFmt ( " PLYX chunk: non-existant company ID: %u " , company_id ) ;
}
uint32 company_flags = SlReadUint32 ( ) ;
// flags are not in use yet, reserve for future expansion
if ( company_flags ! = 0 ) SlErrorCorruptFmt ( " PLYX chunk: unknown company flags: 0x%X " , company_flags ) ;
uint32 settings_count = SlReadUint32 ( ) ;
for ( uint32 j = 0 ; j < settings_count ; j + + ) {
SlObject ( & current_setting , _settings_ext_load_desc ) ;
// flags are not in use yet, reserve for future expansion
if ( current_setting . flags ! = 0 ) SlErrorCorruptFmt ( " PLYX chunk: unknown setting header flags: 0x%X " , current_setting . flags ) ;
if ( skip ) {
SlSkipBytes ( current_setting . setting_length ) ;
continue ;
}
const SettingDesc * setting = NULL ;
// not many company settings, so perform a linear scan
for ( const SettingDesc * desc = _company_settings ; desc - > save . cmd ! = SL_END ; desc + + ) {
if ( desc - > patx_name ! = NULL & & strcmp ( desc - > patx_name , current_setting . name ) = = 0 ) {
setting = desc ;
break ;
}
}
if ( setting ! = NULL ) {
// found setting
const SaveLoad * sld = & ( setting - > save ) ;
size_t read = SlGetBytesRead ( ) ;
void * ptr = GetVariableAddress ( & ( c - > settings ) , sld ) ;
SlObjectMember ( ptr , sld ) ;
if ( SlGetBytesRead ( ) ! = read + current_setting . setting_length ) {
SlErrorCorruptFmt ( " PLYX chunk: setting read length mismatch for setting: '%s' " , current_setting . name ) ;
}
if ( IsNumericType ( sld - > conv ) ) Write_ValidateSetting ( ptr , setting , ReadValue ( ptr , sld - > conv ) ) ;
} else {
DEBUG ( sl , 1 , " PLYX chunk: Could not find company setting: '%s', ignoring " , current_setting . name ) ;
SlSkipBytes ( current_setting . setting_length ) ;
}
}
}
}
/**
* Save handler for settings which go in the PLYX chunk
*/
void SaveSettingsPlyx ( )
{
SettingsExtSave current_setting ;
static const SaveLoad _settings_plyx_desc [ ] = {
SLE_VAR ( SettingsExtSave , flags , SLE_UINT32 ) ,
SLE_STR ( SettingsExtSave , name , SLE_STR , 0 ) ,
SLE_VAR ( SettingsExtSave , setting_length , SLE_UINT32 ) ,
SLE_END ( )
} ;
std : : vector < uint32 > company_setting_counts ;
size_t length = 8 ;
uint32 companies_count = 0 ;
Company * c ;
FOR_ALL_COMPANIES ( c ) {
length + = 12 ;
companies_count + + ;
uint32 setting_count = 0 ;
for ( const SettingDesc * desc = _company_settings ; desc - > save . cmd ! = SL_END ; desc + + ) {
if ( desc - > patx_name = = NULL ) continue ;
uint32 setting_length = SlCalcObjMemberLength ( & ( c - > settings ) , & desc - > save ) ;
if ( ! setting_length ) continue ;
current_setting . name = desc - > patx_name ;
// add length of setting header
length + = SlCalcObjLength ( & current_setting , _settings_ext_save_desc ) ;
// add length of actual setting
length + = setting_length ;
setting_count + + ;
}
company_setting_counts . push_back ( setting_count ) ;
}
SlSetLength ( length ) ;
SlWriteUint32 ( 0 ) ; // flags
SlWriteUint32 ( companies_count ) ; // companies count
size_t index = 0 ;
FOR_ALL_COMPANIES ( c ) {
length + = 12 ;
companies_count + + ;
SlWriteUint32 ( c - > index ) ; // company ID
SlWriteUint32 ( 0 ) ; // flags
SlWriteUint32 ( company_setting_counts [ index ] ) ; // setting count
index + + ;
for ( const SettingDesc * desc = _company_settings ; desc - > save . cmd ! = SL_END ; desc + + ) {
if ( desc - > patx_name = = NULL ) continue ;
uint32 setting_length = SlCalcObjMemberLength ( & ( c - > settings ) , & desc - > save ) ;
if ( ! setting_length ) continue ;
current_setting . flags = 0 ;
current_setting . name = desc - > patx_name ;
current_setting . setting_length = setting_length ;
SlObject ( & current_setting , _settings_plyx_desc ) ;
void * ptr = GetVariableAddress ( & ( c - > settings ) , & desc - > save ) ;
SlObjectMember ( ptr , & desc - > save ) ;
}
}
}
static void Load_OPTS ( )
{
/* Copy over default setting since some might not get loaded in