00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "debug.h"
00008 #include "variables.h"
00009 #include "saveload.h"
00010 #include "md5.h"
00011 #include "network/network_data.h"
00012 #include "newgrf.h"
00013 #include "newgrf_config.h"
00014 #include "core/alloc_func.hpp"
00015 #include "string_func.h"
00016
00017 #include "fileio.h"
00018 #include "fios.h"
00019 #include <sys/stat.h>
00020
00021 #ifdef WIN32
00022 # include <io.h>
00023 #endif
00024
00025
00026 GRFConfig *_all_grfs;
00027 GRFConfig *_grfconfig;
00028 GRFConfig *_grfconfig_newgame;
00029 GRFConfig *_grfconfig_static;
00030
00031
00032
00033 static bool CalcGRFMD5Sum(GRFConfig *config)
00034 {
00035 FILE *f;
00036 Md5 checksum;
00037 uint8 buffer[1024];
00038 size_t len, size;
00039
00040
00041 f = FioFOpenFile(config->filename, "rb", DATA_DIR, &size);
00042 if (f == NULL) return false;
00043
00044
00045 while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
00046 size -= len;
00047 checksum.Append(buffer, len);
00048 }
00049 checksum.Finish(config->md5sum);
00050
00051 FioFCloseFile(f);
00052
00053 return true;
00054 }
00055
00056
00057
00058 bool FillGRFDetails(GRFConfig *config, bool is_static)
00059 {
00060 if (!FioCheckFileExists(config->filename)) {
00061 config->status = GCS_NOT_FOUND;
00062 return false;
00063 }
00064
00065
00066 LoadNewGRFFile(config, CONFIG_SLOT, GLS_FILESCAN);
00067
00068
00069 if (config->grfid == 0 || config->grfid == 0xFFFFFFFF || config->IsOpenTTDBaseGRF()) return false;
00070
00071 if (is_static) {
00072
00073 LoadNewGRFFile(config, 62, GLS_SAFETYSCAN);
00074
00075
00076 if (HasBit(config->flags, GCF_UNSAFE)) return false;
00077 }
00078
00079 return CalcGRFMD5Sum(config);
00080 }
00081
00082
00083 void ClearGRFConfig(GRFConfig **config)
00084 {
00085
00086 if (!HasBit((*config)->flags, GCF_COPY)) {
00087 free((*config)->filename);
00088 free((*config)->name);
00089 free((*config)->info);
00090
00091 if ((*config)->error != NULL) {
00092 free((*config)->error->custom_message);
00093 free((*config)->error->data);
00094 free((*config)->error);
00095 }
00096 }
00097 free(*config);
00098 *config = NULL;
00099 }
00100
00101
00102
00103 void ClearGRFConfigList(GRFConfig **config)
00104 {
00105 GRFConfig *c, *next;
00106 for (c = *config; c != NULL; c = next) {
00107 next = c->next;
00108 ClearGRFConfig(&c);
00109 }
00110 *config = NULL;
00111 }
00112
00113
00119 GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only)
00120 {
00121
00122 ClearGRFConfigList(dst);
00123 for (; src != NULL; src = src->next) {
00124 GRFConfig *c = CallocT<GRFConfig>(1);
00125 *c = *src;
00126 if (src->filename != NULL) c->filename = strdup(src->filename);
00127 if (src->name != NULL) c->name = strdup(src->name);
00128 if (src->info != NULL) c->info = strdup(src->info);
00129 if (src->error != NULL) {
00130 c->error = CallocT<GRFError>(1);
00131 memcpy(c->error, src->error, sizeof(GRFError));
00132 if (src->error->data != NULL) c->error->data = strdup(src->error->data);
00133 if (src->error->custom_message != NULL) c->error->custom_message = strdup(src->error->custom_message);
00134 }
00135
00136 ClrBit(c->flags, GCF_INIT_ONLY);
00137 if (init_only) SetBit(c->flags, GCF_INIT_ONLY);
00138
00139 *dst = c;
00140 dst = &c->next;
00141 }
00142
00143 return dst;
00144 }
00145
00159 static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list)
00160 {
00161 GRFConfig *prev;
00162 GRFConfig *cur;
00163
00164 if (list == NULL) return;
00165
00166 for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) {
00167 if (cur->grfid != list->grfid) continue;
00168
00169 prev->next = cur->next;
00170 ClearGRFConfig(&cur);
00171 cur = prev;
00172 }
00173
00174 RemoveDuplicatesFromGRFConfigList(list->next);
00175 }
00176
00181 void AppendStaticGRFConfigs(GRFConfig **dst)
00182 {
00183 GRFConfig **tail = dst;
00184 while (*tail != NULL) tail = &(*tail)->next;
00185
00186 CopyGRFConfigList(tail, _grfconfig_static, false);
00187 RemoveDuplicatesFromGRFConfigList(*dst);
00188 }
00189
00193 void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el)
00194 {
00195 GRFConfig **tail = dst;
00196 while (*tail != NULL) tail = &(*tail)->next;
00197 *tail = el;
00198
00199 RemoveDuplicatesFromGRFConfigList(*dst);
00200 }
00201
00202
00203
00204 void ResetGRFConfig(bool defaults)
00205 {
00206 CopyGRFConfigList(&_grfconfig, _grfconfig_newgame, !defaults);
00207 AppendStaticGRFConfigs(&_grfconfig);
00208 }
00209
00210
00219 GRFListCompatibility IsGoodGRFConfigList()
00220 {
00221 GRFListCompatibility res = GLC_ALL_GOOD;
00222
00223 for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
00224 const GRFConfig *f = FindGRFConfig(c->grfid, c->md5sum);
00225 if (f == NULL) {
00226 char buf[256];
00227
00228
00229
00230 f = FindGRFConfig(c->grfid);
00231 if (f != NULL) {
00232 md5sumToString(buf, lastof(buf), c->md5sum);
00233 DEBUG(grf, 1, "NewGRF %08X (%s) not found; checksum %s. Compatibility mode on", BSWAP32(c->grfid), c->filename, buf);
00234 SetBit(c->flags, GCF_COMPATIBLE);
00235
00236
00237 if (res != GLC_NOT_FOUND) res = GLC_COMPATIBLE;
00238 goto compatible_grf;
00239 }
00240
00241
00242 md5sumToString(buf, lastof(buf), c->md5sum);
00243 DEBUG(grf, 0, "NewGRF %08X (%s) not found; checksum %s", BSWAP32(c->grfid), c->filename, buf);
00244
00245 c->status = GCS_NOT_FOUND;
00246 res = GLC_NOT_FOUND;
00247 } else {
00248 compatible_grf:
00249 DEBUG(grf, 1, "Loading GRF %08X from %s", BSWAP32(f->grfid), f->filename);
00250
00251
00252
00253
00254
00255 if (!HasBit(c->flags, GCF_COPY)) {
00256 free(c->filename);
00257 c->filename = strdup(f->filename);
00258 memcpy(c->md5sum, f->md5sum, sizeof(c->md5sum));
00259 if (c->name == NULL && f->name != NULL) c->name = strdup(f->name);
00260 if (c->info == NULL && f->info != NULL) c->info = strdup(f->info);
00261 c->error = NULL;
00262 }
00263 }
00264 }
00265
00266 return res;
00267 }
00268
00269 static bool ScanPathAddGrf(const char *filename)
00270 {
00271 GRFConfig *c = CallocT<GRFConfig>(1);
00272 c->filename = strdup(filename);
00273
00274 bool added = true;
00275 if (FillGRFDetails(c, false)) {
00276 if (_all_grfs == NULL) {
00277 _all_grfs = c;
00278 } else {
00279
00280
00281 GRFConfig **pd, *d;
00282 bool stop = false;
00283 for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) {
00284 if (c->grfid == d->grfid && memcmp(c->md5sum, d->md5sum, sizeof(c->md5sum)) == 0) added = false;
00285
00286
00287
00288 if (strcasecmp(c->name, d->name) <= 0) {
00289 stop = true;
00290 } else if (stop) {
00291 break;
00292 }
00293 }
00294 if (added) {
00295 c->next = d;
00296 *pd = c;
00297 }
00298 }
00299 } else {
00300 added = false;
00301 }
00302
00303 if (!added) {
00304
00305
00306 free(c->filename);
00307 free(c->name);
00308 free(c->info);
00309 free(c);
00310 }
00311
00312 return added;
00313 }
00314
00315
00316 static uint ScanPath(const char *path, int basepath_length)
00317 {
00318 extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
00319
00320 uint num = 0;
00321 struct stat sb;
00322 struct dirent *dirent;
00323 DIR *dir;
00324
00325 if (path == NULL || (dir = ttd_opendir(path)) == NULL) return 0;
00326
00327 while ((dirent = readdir(dir)) != NULL) {
00328 const char *d_name = FS2OTTD(dirent->d_name);
00329 char filename[MAX_PATH];
00330
00331 if (!FiosIsValidFile(path, dirent, &sb)) continue;
00332
00333 snprintf(filename, lengthof(filename), "%s%s", path, d_name);
00334
00335 if (sb.st_mode & S_IFDIR) {
00336
00337 if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue;
00338 AppendPathSeparator(filename, lengthof(filename));
00339 num += ScanPath(filename, basepath_length);
00340 } else if (sb.st_mode & S_IFREG) {
00341
00342 char *ext = strrchr(filename, '.');
00343
00344
00345 if (ext == NULL) continue;
00346 if (strcasecmp(ext, ".grf") != 0) continue;
00347
00348 if (ScanPathAddGrf(filename + basepath_length)) num++;
00349 }
00350 }
00351
00352 closedir(dir);
00353
00354 return num;
00355 }
00356
00357 static uint ScanTar(TarFileList::iterator tar)
00358 {
00359 uint num = 0;
00360 const char *filename = (*tar).first.c_str();
00361 const char *ext = strrchr(filename, '.');
00362
00363
00364 if (ext == NULL) return false;
00365 if (strcasecmp(ext, ".grf") != 0) return false;
00366
00367 if (ScanPathAddGrf(filename)) num++;
00368
00369 return num;
00370 }
00371
00378 static int CDECL GRFSorter(const void *p1, const void *p2)
00379 {
00380 const GRFConfig *c1 = *(const GRFConfig **)p1;
00381 const GRFConfig *c2 = *(const GRFConfig **)p2;
00382
00383 return strcmp(c1->name != NULL ? c1->name : c1->filename,
00384 c2->name != NULL ? c2->name : c2->filename);
00385 }
00386
00387
00388 void ScanNewGRFFiles()
00389 {
00390 Searchpath sp;
00391 char path[MAX_PATH];
00392 TarFileList::iterator tar;
00393 uint num = 0;
00394
00395 ClearGRFConfigList(&_all_grfs);
00396
00397 DEBUG(grf, 1, "Scanning for NewGRFs");
00398 FOR_ALL_SEARCHPATHS(sp) {
00399 FioAppendDirectory(path, MAX_PATH, sp, DATA_DIR);
00400 num += ScanPath(path, strlen(path));
00401 }
00402 FOR_ALL_TARS(tar) {
00403 num += ScanTar(tar);
00404 }
00405
00406 DEBUG(grf, 1, "Scan complete, found %d files", num);
00407 if (num == 0 || _all_grfs == NULL) return;
00408
00409
00410
00411
00412 GRFConfig **to_sort = MallocT<GRFConfig*>(num);
00413
00414 uint i = 0;
00415 for (GRFConfig *p = _all_grfs; p != NULL; p = p->next, i++) {
00416 to_sort[i] = p;
00417 }
00418
00419 num = i;
00420
00421 qsort(to_sort, num, sizeof(GRFConfig*), GRFSorter);
00422
00423 for (i = 1; i < num; i++) {
00424 to_sort[i - 1]->next = to_sort[i];
00425 }
00426 to_sort[num - 1]->next = NULL;
00427 _all_grfs = to_sort[0];
00428
00429 free(to_sort);
00430 }
00431
00432
00433
00434 const GRFConfig *FindGRFConfig(uint32 grfid, const uint8 *md5sum)
00435 {
00436 for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) {
00437 if (c->grfid == grfid) {
00438 if (md5sum == NULL) return c;
00439
00440 if (memcmp(md5sum, c->md5sum, sizeof(c->md5sum)) == 0) return c;
00441 }
00442 }
00443
00444 return NULL;
00445 }
00446
00447 #ifdef ENABLE_NETWORK
00448
00450 struct UnknownGRF : public GRFIdentifier {
00451 UnknownGRF *next;
00452 char name[NETWORK_GRF_NAME_LENGTH];
00453 };
00454
00472 char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create)
00473 {
00474 UnknownGRF *grf;
00475 static UnknownGRF *unknown_grfs = NULL;
00476
00477 for (grf = unknown_grfs; grf != NULL; grf = grf->next) {
00478 if (grf->grfid == grfid) {
00479 if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name;
00480 }
00481 }
00482
00483 if (!create) return NULL;
00484
00485 grf = CallocT<UnknownGRF>(1);
00486 grf->grfid = grfid;
00487 grf->next = unknown_grfs;
00488 ttd_strlcpy(grf->name, UNKNOWN_GRF_NAME_PLACEHOLDER, sizeof(grf->name));
00489 memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum));
00490
00491 unknown_grfs = grf;
00492 return grf->name;
00493 }
00494
00495 #endif
00496
00497
00498
00499 GRFConfig *GetGRFConfig(uint32 grfid)
00500 {
00501 GRFConfig *c;
00502
00503 for (c = _grfconfig; c != NULL; c = c->next) {
00504 if (c->grfid == grfid) return c;
00505 }
00506
00507 return NULL;
00508 }
00509
00510
00511
00512 char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last)
00513 {
00514 uint i;
00515
00516
00517 if (c->num_params == 0) return strecpy(dst, "", last);
00518
00519 for (i = 0; i < c->num_params; i++) {
00520 if (i > 0) dst = strecpy(dst, " ", last);
00521 dst += snprintf(dst, last - dst, "%d", c->param[i]);
00522 }
00523 return dst;
00524 }
00525
00527 static const uint32 OPENTTD_GRAPHICS_BASE_GRF_ID = BSWAP32(0xFF4F5400);
00528
00533 bool GRFConfig::IsOpenTTDBaseGRF() const
00534 {
00535 return (this->grfid & 0x00FFFFFF) == OPENTTD_GRAPHICS_BASE_GRF_ID;
00536 }
00537
00538
00539 static const SaveLoad _grfconfig_desc[] = {
00540 SLE_STR(GRFConfig, filename, SLE_STR, 0x40),
00541 SLE_VAR(GRFConfig, grfid, SLE_UINT32),
00542 SLE_ARR(GRFConfig, md5sum, SLE_UINT8, 16),
00543 SLE_ARR(GRFConfig, param, SLE_UINT32, 0x80),
00544 SLE_VAR(GRFConfig, num_params, SLE_UINT8),
00545 SLE_END()
00546 };
00547
00548
00549 static void Save_NGRF()
00550 {
00551 int index = 0;
00552
00553 for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
00554 if (HasBit(c->flags, GCF_STATIC)) continue;
00555 SlSetArrayIndex(index++);
00556 SlObject(c, _grfconfig_desc);
00557 }
00558 }
00559
00560
00561 static void Load_NGRF()
00562 {
00563 ClearGRFConfigList(&_grfconfig);
00564 while (SlIterateArray() != -1) {
00565 GRFConfig *c = CallocT<GRFConfig>(1);
00566 SlObject(c, _grfconfig_desc);
00567 AppendToGRFConfigList(&_grfconfig, c);
00568 }
00569
00570
00571 AppendStaticGRFConfigs(&_grfconfig);
00572 }
00573
00574 extern const ChunkHandler _newgrf_chunk_handlers[] = {
00575 { 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST }
00576 };
00577
00578
00579