(svn r4760) - Newstations: change the way custom stations are allocated when loading from GRF, as the current way was flawed (reallocing memory which is referenced elsewhere)
authorpeter1138
Sat, 06 May 2006 22:20:16 +0000
changeset 3768 5194cf3c57b1
parent 3767 5ca790673789
child 3769 7d3b35126fc1
(svn r4760) - Newstations: change the way custom stations are allocated when loading from GRF, as the current way was flawed (reallocing memory which is referenced elsewhere)
newgrf.c
newgrf.h
--- a/newgrf.c	Sat May 06 22:10:38 2006 +0000
+++ b/newgrf.c	Sat May 06 22:20:16 2006 +0000
@@ -85,6 +85,10 @@
 	/* GSF_AIRCRAFT */ AIRCRAFT_ENGINES_INDEX,
 };
 
+enum {
+	MAX_STATIONS = 256,
+};
+
 static uint16 cargo_allowed[TOTAL_NUM_ENGINES];
 static uint16 cargo_disallowed[TOTAL_NUM_ENGINES];
 
@@ -771,36 +775,48 @@
 
 static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int len)
 {
-	StationSpec *statspec;
+	StationSpec **statspec;
 	byte *buf = *bufp;
 	int i;
 	bool ret = false;
 
+	if (stid + numinfo > MAX_STATIONS) {
+		grfmsg(GMS_WARN, "StationChangeInfo: Station %u is invalid, max %u, ignoring.", stid + numinfo, MAX_STATIONS);
+		return false;
+	}
+
 	/* Allocate station specs if necessary */
-	if (_cur_grffile->num_stations < stid + numinfo) {
-		_cur_grffile->stations = realloc(_cur_grffile->stations, (stid + numinfo) * sizeof(*_cur_grffile->stations))
-;
-
-		while (_cur_grffile->num_stations < stid + numinfo) {
-			memset(&_cur_grffile->stations[_cur_grffile->num_stations], 0, sizeof(*_cur_grffile->stations));
-			_cur_grffile->num_stations++;
+	if (_cur_grffile->stations == NULL) _cur_grffile->stations = calloc(MAX_STATIONS, sizeof(*_cur_grffile->stations));
+
+	statspec = &_cur_grffile->stations[stid];
+
+	if (prop != 0x08) {
+		/* Check that all stations we are modifying are defined. */
+		FOR_EACH_OBJECT {
+			if (statspec[i] == NULL) {
+				grfmsg(GMS_NOTICE, "StationChangeInfo: Attempt to modify undefined station %u, ignoring.", stid + i);
+				return false;
+			}
 		}
 	}
 
-	statspec = &_cur_grffile->stations[stid];
-
 	switch (prop) {
 		case 0x08: /* Class ID */
 			FOR_EACH_OBJECT {
+				uint32 classid;
+
+				/* Property 0x08 is special; it is where the station is allocated */
+				if (statspec[i] == NULL) statspec[i] = calloc(1, sizeof(*statspec[i]));
+
 				/* Swap classid because we read it in BE meaning WAYP or DFLT */
-				uint32 classid = grf_load_dword(&buf);
-				statspec[i].sclass = AllocateStationClass(BSWAP32(classid));
+				classid = grf_load_dword(&buf);
+				statspec[i]->sclass = AllocateStationClass(BSWAP32(classid));
 			}
 			break;
 
 		case 0x09: /* Define sprite layout */
 			FOR_EACH_OBJECT {
-				StationSpec *statspec = &_cur_grffile->stations[stid + i];
+				StationSpec *statspec = _cur_grffile->stations[stid + i];
 				uint t;
 
 				statspec->tiles = grf_load_extended(&buf);
@@ -846,9 +862,9 @@
 
 		case 0x0A: /* Copy sprite layout */
 			FOR_EACH_OBJECT {
-				StationSpec *statspec = &_cur_grffile->stations[stid + i];
+				StationSpec *statspec = _cur_grffile->stations[stid + i];
 				byte srcid = grf_load_byte(&buf);
-				const StationSpec *srcstatspec = &_cur_grffile->stations[srcid];
+				const StationSpec *srcstatspec = _cur_grffile->stations[srcid];
 
 				statspec->tiles = srcstatspec->tiles;
 				statspec->renderdata = srcstatspec->renderdata;
@@ -857,20 +873,20 @@
 			break;
 
 		case 0x0B: /* Callback mask */
-			FOR_EACH_OBJECT statspec[i].callbackmask = grf_load_byte(&buf);
+			FOR_EACH_OBJECT statspec[i]->callbackmask = grf_load_byte(&buf);
 			break;
 
 		case 0x0C: /* Disallowed number of platforms */
-			FOR_EACH_OBJECT statspec[i].disallowed_platforms = grf_load_byte(&buf);
+			FOR_EACH_OBJECT statspec[i]->disallowed_platforms = grf_load_byte(&buf);
 			break;
 
 		case 0x0D: /* Disallowed platform lengths */
-			FOR_EACH_OBJECT statspec[i].disallowed_lengths = grf_load_byte(&buf);
+			FOR_EACH_OBJECT statspec[i]->disallowed_lengths = grf_load_byte(&buf);
 			break;
 
 		case 0x0E: /* Define custom layout */
 			FOR_EACH_OBJECT {
-				StationSpec *statspec = &_cur_grffile->stations[stid + i];
+				StationSpec *statspec = _cur_grffile->stations[stid + i];
 
 				while (buf < *bufp + len) {
 					byte length = grf_load_byte(&buf);
@@ -929,27 +945,27 @@
 			break;
 
 		case 0x10: /* Little/lots cargo threshold */
-			FOR_EACH_OBJECT statspec[i].cargo_threshold = grf_load_word(&buf);
+			FOR_EACH_OBJECT statspec[i]->cargo_threshold = grf_load_word(&buf);
 			break;
 
 		case 0x11: /* Pylon placement */
-			FOR_EACH_OBJECT statspec[i].pylons = grf_load_byte(&buf);
+			FOR_EACH_OBJECT statspec[i]->pylons = grf_load_byte(&buf);
 			break;
 
 		case 0x12: /* Cargo types for random triggers */
-			FOR_EACH_OBJECT statspec[i].cargo_triggers = grf_load_dword(&buf);
+			FOR_EACH_OBJECT statspec[i]->cargo_triggers = grf_load_dword(&buf);
 			break;
 
 		case 0x13: /* General flags */
-			FOR_EACH_OBJECT statspec[i].flags = grf_load_byte(&buf);
+			FOR_EACH_OBJECT statspec[i]->flags = grf_load_byte(&buf);
 			break;
 
 		case 0x14: /* Overhead wire placement */
-			FOR_EACH_OBJECT statspec[i].wires = grf_load_byte(&buf);
+			FOR_EACH_OBJECT statspec[i]->wires = grf_load_byte(&buf);
 			break;
 
 		case 0x15: /* Blocked tiles */
-			FOR_EACH_OBJECT statspec[i].blocked = grf_load_byte(&buf);
+			FOR_EACH_OBJECT statspec[i]->blocked = grf_load_byte(&buf);
 			break;
 
 		default:
@@ -1569,7 +1585,7 @@
 
 		for (i = 0; i < idcount; i++) {
 			uint8 stid = buf[3 + i];
-			StationSpec *statspec = &_cur_grffile->stations[stid];
+			StationSpec *statspec = _cur_grffile->stations[stid];
 			byte *bp = &buf[4 + idcount];
 
 			for (c = 0; c < cidcount; c++) {
@@ -1601,7 +1617,7 @@
 
 			for (i = 0; i < idcount; i++) {
 				uint8 stid = buf[3 + i];
-				StationSpec *statspec = &_cur_grffile->stations[stid];
+				StationSpec *statspec = _cur_grffile->stations[stid];
 
 				statspec->spritegroup[GC_DEFAULT] = _cur_grffile->spritegroups[groupid];
 				statspec->grfid = _cur_grffile->grfid;
@@ -1782,19 +1798,19 @@
 				default:
 					switch (GB(id, 8, 8)) {
 						case 0xC4: /* Station class name */
-							if (GB(id, 0, 8) >= _cur_grffile->num_stations) {
+							if (_cur_grffile->stations == NULL || _cur_grffile->stations[GB(id, 0, 8)] == NULL) {
 								grfmsg(GMS_WARN, "VehicleNewName: Attempt to name undefined station 0x%X, ignoring.", GB(id, 0, 8));
 							} else {
-								StationClassID sclass = _cur_grffile->stations[GB(id, 0, 8)].sclass;
+								StationClassID sclass = _cur_grffile->stations[GB(id, 0, 8)]->sclass;
 								SetStationClassName(sclass, AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name));
 							}
 							break;
 
 						case 0xC5: /* Station name */
-							if (GB(id, 0, 8) >= _cur_grffile->num_stations) {
+							if (_cur_grffile->stations == NULL || _cur_grffile->stations[GB(id, 0, 8)] == NULL) {
 								grfmsg(GMS_WARN, "VehicleNewName: Attempt to name undefined station 0x%X, ignoring.", GB(id, 0, 8));
 							} else {
-								_cur_grffile->stations[GB(id, 0, 8)].name = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name);
+								_cur_grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name);
 							}
 							break;
 
@@ -2482,9 +2498,10 @@
 	uint t;
 
 	for (file = _first_grffile; file != NULL; file = file->next) {
-		for (i = 0; i < file->num_stations; i++) {
-			if (file->stations[i].grfid != file->grfid) continue;
-			statspec = &file->stations[i];
+		if (file->stations == NULL) continue;
+		for (i = 0; i < MAX_STATIONS; i++) {
+			if (file->stations[i] == NULL) continue;
+			statspec = file->stations[i];
 
 			/* Release renderdata, if it wasn't copied from another custom station spec  */
 			if (!statspec->copied_renderdata) {
@@ -2495,12 +2512,14 @@
 			}
 
 			// TODO: Release platforms and layouts
+
+			/* Release this station */
+			free(statspec);
 		}
 
 		/* Free and reset the station data */
 		free(file->stations);
 		file->stations = NULL;
-		file->num_stations = 0;
 	}
 }
 
--- a/newgrf.h	Sat May 06 22:10:38 2006 +0000
+++ b/newgrf.h	Sat May 06 22:20:16 2006 +0000
@@ -41,8 +41,7 @@
 	int spritegroups_count;
 	SpriteGroup **spritegroups;
 
-	uint num_stations;
-	StationSpec *stations;
+	StationSpec **stations;
 
 	uint32 param[0x80];
 	uint param_end; /// one more than the highest set parameter