(svn r14203) -Codechange: [NewGRF] Disable a GRF if it contains an unknown property, or tries to assign an invalid ID.
authorpeter1138
Sun, 31 Aug 2008 16:41:27 +0000
changeset 10043 7f8f7df729d3
parent 10042 b77001494a91
child 10044 a324ba35da2e
(svn r14203) -Codechange: [NewGRF] Disable a GRF if it contains an unknown property, or tries to assign an invalid ID.
src/lang/english.txt
src/newgrf.cpp
--- a/src/lang/english.txt	Sun Aug 31 15:46:14 2008 +0000
+++ b/src/lang/english.txt	Sun Aug 31 16:41:27 2008 +0000
@@ -3217,6 +3217,8 @@
 STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED                        :Too many NewGRFs are loaded.
 STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC                       :Loading {RAW_STRING} as static NewGRF with {RAW_STRING} could cause desyncs.
 STR_NEWGRF_ERROR_UNEXPECTED_SPRITE                              :Unexpected sprite.
+STR_NEWGRF_ERROR_UNKNOWN_PROPERTY                               :Unknown Action 0 property.
+STR_NEWGRF_ERROR_INVALID_ID                                     :Attempt to use invalid ID.
 
 STR_NEWGRF_PRESET_LIST_TIP                                      :{BLACK}Load the selected preset
 STR_NEWGRF_PRESET_SAVE                                          :{BLACK}Save preset
--- a/src/newgrf.cpp	Sun Aug 31 15:46:14 2008 +0000
+++ b/src/newgrf.cpp	Sun Aug 31 16:41:27 2008 +0000
@@ -437,9 +437,16 @@
 	}
 }
 
-typedef bool (*VCI_Handler)(uint engine, int numinfo, int prop, byte **buf, int len);
-
-static bool CommonVehicleChangeInfo(EngineInfo *ei, int prop, byte **buf)
+enum ChangeInfoResult {
+	CIR_SUCCESS,    ///< Variable was parsed and read
+	CIR_UNHANDLED,  ///< Variable was parsed but unread
+	CIR_UNKNOWN,    ///< Variable is unknown
+	CIR_INVALID_ID, ///< Attempt to modify an invalid ID
+};
+
+typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, byte **buf, int len);
+
+static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, byte **buf)
 {
 	switch (prop) {
 		case 0x00: // Introduction date
@@ -471,16 +478,16 @@
 			break;
 
 		default:
-			return false;
-	}
-
-	return true;
+			return CIR_UNKNOWN;
+	}
+
+	return CIR_SUCCESS;
 }
 
-static bool RailVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	for (int i = 0; i < numinfo; i++) {
 		Engine *e = GetNewEngine(_cur_grffile, VEH_TRAIN, engine + i);
@@ -655,7 +662,7 @@
 			case 0x20: // Air drag
 				/** @todo Air drag for trains. */
 				grf_load_byte(&buf);
-				ret = true;
+				ret = CIR_UNHANDLED;
 				break;
 
 			case 0x21: // Shorter vehicle
@@ -707,7 +714,7 @@
 				break;
 
 			default:
-				ret = !CommonVehicleChangeInfo(ei, prop, &buf);
+				ret = CommonVehicleChangeInfo(ei, prop, &buf);
 				break;
 		}
 	}
@@ -716,10 +723,10 @@
 	return ret;
 }
 
-static bool RoadVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	for (int i = 0; i < numinfo; i++) {
 		Engine *e = GetNewEngine(_cur_grffile, VEH_ROAD, engine + i);
@@ -796,7 +803,7 @@
 				 * computations (called rvpower in TTDPatch) is just
 				 * missing in OTTD yet. --pasky */
 				grf_load_byte(&buf);
-				ret = true;
+				ret = CIR_UNHANDLED;
 				break;
 
 			case 0x16: // Cargos available for refitting
@@ -811,7 +818,7 @@
 			case 0x19: // Air drag
 				/** @todo Tractive effort and air drag for road vehicles. */
 				grf_load_byte(&buf);
-				ret = true;
+				ret = CIR_UNHANDLED;
 				break;
 
 			case 0x1A: // Refit cost
@@ -844,7 +851,7 @@
 				break;
 
 			default:
-				ret = !CommonVehicleChangeInfo(ei, prop, &buf);
+				ret = CommonVehicleChangeInfo(ei, prop, &buf);
 				break;
 		}
 	}
@@ -853,10 +860,10 @@
 	return ret;
 }
 
-static bool ShipVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	for (int i = 0; i < numinfo; i++) {
 		Engine *e = GetNewEngine(_cur_grffile, VEH_SHIP, engine + i);
@@ -928,7 +935,7 @@
 			case 0x15: // Canal speed fraction
 				/** @todo Speed fractions for ships on oceans and canals */
 				grf_load_byte(&buf);
-				ret = true;
+				ret = CIR_UNHANDLED;
 				break;
 
 			case 0x16: // Retire vehicle early
@@ -957,7 +964,7 @@
 				break;
 
 			default:
-				ret = !CommonVehicleChangeInfo(ei, prop, &buf);
+				ret = CommonVehicleChangeInfo(ei, prop, &buf);
 				break;
 		}
 	}
@@ -966,10 +973,10 @@
 	return ret;
 }
 
-static bool AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	for (int i = 0; i < numinfo; i++) {
 		Engine *e = GetNewEngine(_cur_grffile, VEH_AIRCRAFT, engine + i);
@@ -1066,7 +1073,7 @@
 				break;
 
 			default:
-				ret = !CommonVehicleChangeInfo(ei, prop, &buf);
+				ret = CommonVehicleChangeInfo(ei, prop, &buf);
 				break;
 		}
 	}
@@ -1075,14 +1082,14 @@
 	return ret;
 }
 
-static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (stid + numinfo > MAX_STATIONS) {
 		grfmsg(1, "StationChangeInfo: Station %u is invalid, max %u, ignoring", stid + numinfo, MAX_STATIONS);
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	/* Allocate station specs if necessary */
@@ -1094,7 +1101,7 @@
 		/* Check that the station we are modifying is defined. */
 		if (statspec == NULL && prop != 0x08) {
 			grfmsg(2, "StationChangeInfo: Attempt to modify undefined station %u, ignoring", stid + i);
-			return false;
+			return CIR_INVALID_ID;
 		}
 
 		switch (prop) {
@@ -1275,7 +1282,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -1284,14 +1291,14 @@
 	return ret;
 }
 
-static bool CanalChangeInfo(uint id, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (id + numinfo > CF_END) {
 		grfmsg(1, "CanalChangeInfo: Canal feature %u is invalid, max %u, ignoreing", id + numinfo, CF_END);
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	for (int i = 0; i < numinfo; i++) {
@@ -1307,7 +1314,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -1316,14 +1323,14 @@
 	return ret;
 }
 
-static bool BridgeChangeInfo(uint brid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (brid + numinfo > MAX_BRIDGES) {
 		grfmsg(1, "BridgeChangeInfo: Bridge %u is invalid, max %u, ignoring", brid + numinfo, MAX_BRIDGES);
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	for (int i = 0; i < numinfo; i++) {
@@ -1406,7 +1413,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -1415,14 +1422,14 @@
 	return ret;
 }
 
-static bool TownHouseChangeInfo(uint hid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (hid + numinfo > HOUSE_MAX) {
 		grfmsg(1, "TownHouseChangeInfo: Too many houses loaded (%u), max (%u). Ignoring.", hid + numinfo, HOUSE_MAX);
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	/* Allocate house specs if they haven't been allocated already. */
@@ -1435,7 +1442,7 @@
 
 		if (prop != 0x08 && housespec == NULL) {
 			grfmsg(2, "TownHouseChangeInfo: Attempt to modify undefined house %u. Ignoring.", hid + i);
-			return false;
+			return CIR_INVALID_ID;
 		}
 
 		switch (prop) {
@@ -1618,7 +1625,7 @@
 			case 0x20: { // @todo Cargo acceptance watch list
 				byte count = grf_load_byte(&buf);
 				for (byte j = 0; j < count; j++) grf_load_byte(&buf);
-				ret = true;
+				ret = CIR_UNHANDLED;
 			} break;
 
 			case 0x21: // long introduction year
@@ -1630,7 +1637,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -1639,10 +1646,10 @@
 	return ret;
 }
 
-static bool GlobalVarChangeInfo(uint gvid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	for (int i = 0; i < numinfo; i++) {
 		switch (prop) {
@@ -1759,7 +1766,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -1768,14 +1775,14 @@
 	return ret;
 }
 
-static bool CargoChangeInfo(uint cid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (cid + numinfo > NUM_CARGO) {
 		grfmsg(2, "CargoChangeInfo: Cargo type %d out of range (max %d)", cid + numinfo, NUM_CARGO - 1);
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	for (int i = 0; i < numinfo; i++) {
@@ -1884,7 +1891,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -1894,14 +1901,14 @@
 }
 
 
-static bool SoundEffectChangeInfo(uint sid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (_cur_grffile->sound_offset == 0) {
 		grfmsg(1, "SoundEffectChangeInfo: No effects defined, skipping");
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	for (int i = 0; i < numinfo; i++) {
@@ -1909,7 +1916,7 @@
 
 		if (sound >= GetNumSounds()) {
 			grfmsg(1, "SoundEffectChangeInfo: Sound %d not defined (max %d)", sound, GetNumSounds());
-			return false;
+			return CIR_INVALID_ID;
 		}
 
 		switch (prop) {
@@ -1936,7 +1943,7 @@
 			} break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -1945,14 +1952,14 @@
 	return ret;
 }
 
-static bool IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (indtid + numinfo > NUM_INDUSTRYTILES) {
 		grfmsg(1, "IndustryTilesChangeInfo: Too many industry tiles loaded (%u), max (%u). Ignoring.", indtid + numinfo, NUM_INDUSTRYTILES);
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	/* Allocate industry tile specs if they haven't been allocated already. */
@@ -1965,7 +1972,7 @@
 
 		if (prop != 0x08 && tsp == NULL) {
 			grfmsg(2, "IndustryTilesChangeInfo: Attempt to modify undefined industry tile %u. Ignoring.", indtid + i);
-			return false;
+			return CIR_INVALID_ID;
 		}
 
 		switch (prop) {
@@ -2046,7 +2053,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -2055,14 +2062,14 @@
 	return ret;
 }
 
-static bool IndustriesChangeInfo(uint indid, int numinfo, int prop, byte **bufp, int len)
+static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, byte **bufp, int len)
 {
 	byte *buf = *bufp;
-	bool ret = false;
+	ChangeInfoResult ret = CIR_SUCCESS;
 
 	if (indid + numinfo > NUM_INDUSTRYTYPES) {
 		grfmsg(1, "IndustriesChangeInfo: Too many industries loaded (%u), max (%u). Ignoring.", indid + numinfo, NUM_INDUSTRYTYPES);
-		return false;
+		return CIR_INVALID_ID;
 	}
 
 	grfmsg(1, "IndustriesChangeInfo: newid %u", indid);
@@ -2077,7 +2084,7 @@
 
 		if (prop != 0x08 && indsp == NULL) {
 			grfmsg(2, "IndustriesChangeInfo: Attempt to modify undefined industry %u. Ignoring.", indid + i);
-			return false;
+			return CIR_INVALID_ID;
 		}
 
 		switch (prop) {
@@ -2307,7 +2314,7 @@
 				break;
 
 			default:
-				ret = true;
+				ret = CIR_UNKNOWN;
 				break;
 		}
 	}
@@ -2368,8 +2375,27 @@
 	while (numprops-- && buf < bufend) {
 		uint8 prop = grf_load_byte(&buf);
 
-		if (handler[feature](engine, numinfo, prop, &buf, bufend - buf)) {
-			grfmsg(1, "FeatureChangeInfo: Ignoring property 0x%02X of feature 0x%02X (not implemented)", prop, feature);
+		ChangeInfoResult cir = handler[feature](engine, numinfo, prop, &buf, bufend - buf);
+		switch (cir) {
+			case CIR_SUCCESS:
+				break;
+
+			case CIR_UNHANDLED:
+				grfmsg(1, "FeatureChangeInfo: Ignoring property 0x%02X of feature 0x%02X (not implemented)", prop, feature);
+				break;
+
+			case CIR_UNKNOWN:
+				grfmsg(0, "FeatureChangeInfo: Unknown property 0x%02X of feature 0x%02X, disabling", prop, feature);
+				/* Fall through */
+
+			case CIR_INVALID_ID:
+				/* No debug message for an invalid ID, as it has already been output */
+				_skip_sprites = -1;
+				_cur_grfconfig->status = GCS_DISABLED;
+				_cur_grfconfig->error  = CallocT<GRFError>(1);
+				_cur_grfconfig->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
+				_cur_grfconfig->error->message  = (cir == CIR_INVALID_ID) ? STR_NEWGRF_ERROR_INVALID_ID : STR_NEWGRF_ERROR_UNKNOWN_PROPERTY;
+				return;
 		}
 	}
 }