Fix Action 0 mapped property length handling

Fix case when Num-info != 1
pull/73/head
Jonathan G Rennison 6 years ago
parent 2bb6877f18
commit 04536952ee

@ -114,14 +114,15 @@
Note that even when using fallback mode 0, above, if the property mapping feature is not present, then use of the mapped property ID in an Action 0 is an error.
</p>
<h4>Format of remapped properties</h4>
All properties which are mapped by the mechanism have the format:
All properties which are mapped by this mechanism have the format:
<table>
<tr><th>Size</th><th>Name</th><th>Meaning</th></tr>
<tr><td>B*</td><td>num</td><td>Size of the data in bytes</td></tr>
<tr><td>V</td><td>data</td><td>Property data</td></tr>
</table>
Note that num is an extended byte, see <a href="https://newgrf-specs.tt-wiki.net/wiki/GRFActionsDetailed">GRFActionsDetailed</a>.<br />
If the size of the data does provided is not valid for the given property, the attempt to set the property MAY be ignored or partially applied.
If the size of the data does provided is not valid for the given property, the attempt to set the property MAY be ignored or partially applied.<br />
Note that each use of the mapped property ID is followed by Num-info iterations of the size and data pair above. See: <a href="https://newgrf-specs.tt-wiki.net/wiki/Action0">Action 0 Specification</a>.
<h4>Example NFO:</h4>
<pre>
// Map station property "sample_station_property" to property id 0xF8, and set bit 4 of global variable 0x8D if successful

@ -991,7 +991,7 @@ enum ChangeInfoResult {
CIR_INVALID_ID, ///< Attempt to modify an invalid ID
};
typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, ByteReader *buf);
typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf);
static ChangeInfoResult HandleAction0PropertyDefault(ByteReader *buf, int prop)
{
@ -1003,14 +1003,26 @@ static ChangeInfoResult HandleAction0PropertyDefault(ByteReader *buf, int prop)
case A0RPI_UNKNOWN_ERROR:
return CIR_DISABLED;
case A0RPI_SKIPPED_IGNORE:
return CIR_SUCCESS;
default:
return CIR_UNKNOWN;
}
}
static bool MappedPropertyLengthMismatch(ByteReader *buf, uint expected_size, const GRFFilePropertyRemapEntry *mapping_entry)
{
uint length = buf->ReadExtendedByte();
if (length != expected_size) {
if (mapping_entry != NULL) {
grfmsg(2, "Ignoring use of mapped property: %s, feature: %X, mapped to: %X, with incorrect data size: %u instead of %u",
mapping_entry->name, mapping_entry->feature, mapping_entry->property_id, length, expected_size);
}
buf->Skip(length);
return true;
} else {
return false;
}
}
/**
* Define properties common to all vehicles
* @param ei Engine info.
@ -1018,7 +1030,7 @@ static ChangeInfoResult HandleAction0PropertyDefault(ByteReader *buf, int prop)
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteReader *buf)
static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
switch (prop) {
case 0x00: // Introduction date
@ -1061,7 +1073,7 @@ static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteRe
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -1339,7 +1351,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop
}
default:
ret = CommonVehicleChangeInfo(ei, prop, buf);
ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
break;
}
}
@ -1355,7 +1367,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -1527,7 +1539,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop
}
default:
ret = CommonVehicleChangeInfo(ei, prop, buf);
ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
break;
}
}
@ -1543,7 +1555,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -1699,7 +1711,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop
}
default:
ret = CommonVehicleChangeInfo(ei, prop, buf);
ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
break;
}
}
@ -1715,7 +1727,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -1853,7 +1865,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int
break;
default:
ret = CommonVehicleChangeInfo(ei, prop, buf);
ret = CommonVehicleChangeInfo(ei, prop, mapping_entry, buf);
break;
}
}
@ -1869,7 +1881,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -2116,7 +2128,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -2154,7 +2166,7 @@ static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteRead
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -2327,7 +2339,7 @@ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader *buf)
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -2600,7 +2612,7 @@ static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
/* Properties which are handled as a whole */
switch (prop) {
@ -2815,7 +2827,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By
return ret;
}
static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
/* Properties which are handled as a whole */
switch (prop) {
@ -2886,7 +2898,7 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, B
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -3025,7 +3037,7 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -3120,7 +3132,7 @@ static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader *buf)
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -3384,7 +3396,7 @@ static void CleanIndustryTileTable(IndustrySpec *ind)
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -3804,7 +3816,7 @@ static void DuplicateTileTable(AirportSpec *as)
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -4022,7 +4034,7 @@ static ChangeInfoResult IgnoreObjectProperty(uint prop, ByteReader *buf)
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -4153,7 +4165,7 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea
* @param buf The property value.
* @return ChangeInfoResult.
*/
static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -4283,7 +4295,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR
return ret;
}
static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -4363,7 +4375,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte
return ret;
}
static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, ByteReader *buf)
static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
{
ChangeInfoResult ret = CIR_SUCCESS;
@ -4482,7 +4494,15 @@ static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uin
}
}
static int ReadAction0PropertyID(ByteReader *buf, uint8 feature)
struct GRFFilePropertyDescriptor {
int prop;
const GRFFilePropertyRemapEntry *entry;
GRFFilePropertyDescriptor(int prop, const GRFFilePropertyRemapEntry *entry)
: prop(prop), entry(entry) {}
};
static GRFFilePropertyDescriptor ReadAction0PropertyID(ByteReader *buf, uint8 feature)
{
uint8 raw_prop = buf->ReadByte();
const GRFFilePropertyRemapSet &remap = _cur.grffile->action0_property_remaps[feature];
@ -4499,22 +4519,10 @@ static int ReadAction0PropertyID(ByteReader *buf, uint8 feature)
error->param_value[2] = raw_prop;
} else if (prop == A0RPI_UNKNOWN_IGNORE) {
grfmsg(2, "Ignoring unimplemented mapped property: %s, feature: %X, mapped to: %X", def.name, def.feature, raw_prop);
} else {
if (HasBit(def.flags, GFPRE_CHECK_SIZE)) {
uint length = buf->ReadExtendedByte();
if (length != def.expected_size) {
grfmsg(2, "Ignoring use of mapped property: %s, feature: %X, mapped to: %X, with incorrect data size: %u instead of %u",
def.name, def.feature, raw_prop, length, def.expected_size);
buf->Skip(length);
prop = A0RPI_SKIPPED_IGNORE;
}
} else {
prop |= A0RPI_CHECK_PROPERTY_LENGTH;
}
}
return prop;
return GRFFilePropertyDescriptor(prop, &def);
} else {
return raw_prop;
return GRFFilePropertyDescriptor(raw_prop, NULL);
}
}
@ -4571,10 +4579,10 @@ static void FeatureChangeInfo(ByteReader *buf)
SetBit(_cur.grffile->grf_features, feature);
while (numprops-- && buf->HasData()) {
int prop = ReadAction0PropertyID(buf, feature);
GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
ChangeInfoResult cir = handler[feature](engine, numinfo, prop, buf);
if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return;
ChangeInfoResult cir = handler[feature](engine, numinfo, desc.prop, desc.entry, buf);
if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, desc.prop)) return;
}
}
@ -4587,14 +4595,14 @@ static void SafeChangeInfo(ByteReader *buf)
buf->ReadExtendedByte(); // id
if (feature == GSF_BRIDGES && numprops == 1) {
int prop = ReadAction0PropertyID(buf, feature);
GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
/* Bridge property 0x0D is redefinition of sprite layout tables, which
* is considered safe. */
if (prop == 0x0D) return;
if (desc.prop == 0x0D) return;
} else if (feature == GSF_GLOBALVAR && numprops == 1) {
int prop = ReadAction0PropertyID(buf, feature);
GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
/* Engine ID Mappings are safe, if the source is static */
if (prop == 0x11) {
if (desc.prop == 0x11) {
bool is_safe = true;
for (uint i = 0; i < numinfo; i++) {
uint32 s = buf->ReadDWord();
@ -4627,25 +4635,25 @@ static void ReserveChangeInfo(ByteReader *buf)
uint8 index = buf->ReadExtendedByte();
while (numprops-- && buf->HasData()) {
int prop = ReadAction0PropertyID(buf, feature);
GRFFilePropertyDescriptor desc = ReadAction0PropertyID(buf, feature);
ChangeInfoResult cir = CIR_SUCCESS;
switch (feature) {
default: NOT_REACHED();
case GSF_CARGOES:
cir = CargoChangeInfo(index, numinfo, prop, buf);
cir = CargoChangeInfo(index, numinfo, desc.prop, desc.entry, buf);
break;
case GSF_GLOBALVAR:
cir = GlobalVarReserveInfo(index, numinfo, prop, buf);
cir = GlobalVarReserveInfo(index, numinfo, desc.prop, desc.entry, buf);
break;
case GSF_RAILTYPES:
cir = RailTypeReserveInfo(index, numinfo, prop, buf);
cir = RailTypeReserveInfo(index, numinfo, desc.prop, desc.entry, buf);
break;
}
if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return;
if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, desc.prop)) return;
}
}
@ -8074,11 +8082,7 @@ struct GRFPropertyMapAction {
entry.name = info->name;
entry.id = info->id;
entry.feature = this->feature;
entry.flags = 0;
if (info->expected_size >= 0) {
SetBit(entry.flags, GFPRE_CHECK_SIZE);
entry.expected_size = info->expected_size;
}
entry.property_id = this->prop_id;
success = true;
break;
}
@ -8102,7 +8106,7 @@ struct GRFPropertyMapAction {
entry.name = str_store;
entry.id = (this->fallback_mode == A0REM_IGNORE) ? A0RPI_UNKNOWN_IGNORE : A0RPI_UNKNOWN_ERROR;
entry.feature = this->feature;
entry.flags = 0;
entry.property_id = this->prop_id;
}
}
}

@ -106,7 +106,6 @@ enum Action0RemapPropertyIds {
A0RPI_CHECK_PROPERTY_LENGTH = 0x10000,
A0RPI_UNKNOWN_IGNORE = 0x200,
A0RPI_UNKNOWN_ERROR,
A0RPI_SKIPPED_IGNORE,
};
enum Action0RemapFallbackMode {
@ -120,34 +119,26 @@ struct GRFPropertyMapDefinition {
const char *name; // NULL indicates the end of the list
int id;
uint8 feature;
int expected_size;
/** Create empty object used to identify the end of a list. */
GRFPropertyMapDefinition() :
name(NULL),
id(0),
feature(0),
expected_size(0)
feature(0)
{}
GRFPropertyMapDefinition(uint8 feature, int id, const char *name, int expected_size = -1) :
GRFPropertyMapDefinition(uint8 feature, int id, const char *name) :
name(name),
id(id),
feature(feature),
expected_size(expected_size)
feature(feature)
{}
};
enum GFPRE_Flags {
GFPRE_CHECK_SIZE,
};
struct GRFFilePropertyRemapEntry {
const char *name = nullptr;
int id = 0;
uint8 feature = 0;
uint8 flags = 0;
uint16 expected_size = 0;
uint8 property_id = 0;
};
struct GRFFilePropertyRemapSet {

Loading…
Cancel
Save