24 #define fetch_metadata(name) \ 25 item = metadata->GetItem(name, false); \ 26 if (item == NULL || StrEmpty(item->value)) { \ 27 DEBUG(grf, 0, "Base " SET_TYPE "set detail loading: %s field missing.", name); \ 28 DEBUG(grf, 0, " Is %s readable for the user running OpenTTD?", full_filename); \ 40 template <
class T,
size_t Tnum_files,
bool Tsearch_in_tars>
53 for (
const IniItem *item = metadata->
item; item != NULL; item = item->
next) {
54 if (strncmp(
"description.", item->
name, 12) != 0)
continue;
60 for (uint i = 0; item->
value[i] !=
'\0' && i < 4; i++) {
61 this->shortname |= ((uint8)item->
value[i]) << (i * 8);
65 this->version = atoi(item->
value);
67 item = metadata->
GetItem(
"fallback",
false);
68 this->fallback = (item != NULL && strcmp(item->
value,
"0") != 0 && strcmp(item->
value,
"false") != 0);
74 for (uint i = 0; i < Tnum_files; i++) {
75 MD5File *file = &this->files[i];
78 if (item == NULL || (item->
value == NULL && !allow_empty_filename)) {
83 const char *filename = item->
value;
84 if (filename == NULL) {
95 item = md5s->
GetItem(filename,
false);
96 if (item == NULL || item->
value == NULL) {
97 DEBUG(grf, 0,
"No MD5 checksum specified for: %s (in %s)", filename, full_filename);
100 char *c = item->
value;
101 for (uint i = 0; i <
sizeof(file->
hash) * 2; i++, c++) {
103 if (
'0' <= *c && *c <=
'9') {
105 }
else if (
'a' <= *c && *c <=
'f') {
107 }
else if (
'A' <= *c && *c <=
'F') {
110 DEBUG(grf, 0,
"Malformed MD5 checksum specified for: %s (in %s)", filename, full_filename);
114 file->
hash[i / 2] = j << 4;
116 file->
hash[i / 2] |= j;
121 item = origin->
GetItem(filename,
false);
122 if (item == NULL) item = origin->
GetItem(
"default",
false);
124 DEBUG(grf, 1,
"No origin warning message specified for: %s", filename);
141 DEBUG(grf, 1,
"MD5 checksum mismatch for: %s (in %s)", filename, full_filename);
146 DEBUG(grf, 1,
"The file %s specified in %s is missing", filename, full_filename);
154 template <
class Tbase_set>
158 DEBUG(grf, 1,
"Checking %s for base " SET_TYPE " set", filename);
160 Tbase_set *
set =
new Tbase_set();
164 char *path =
stredup(filename + basepath_length);
165 char *psep = strrchr(path, PATHSEPCHAR);
172 if (set->FillSetDetails(ini, path, filename)) {
173 Tbase_set *duplicate = NULL;
175 if (strcmp(c->name, set->name) == 0 || c->shortname ==
set->shortname) {
180 if (duplicate != NULL) {
182 if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) ||
183 duplicate->valid_files >
set->valid_files) {
184 DEBUG(grf, 1,
"Not adding %s (%i) as base " SET_TYPE " set (duplicate, %s)", set->name, set->version,
185 duplicate->valid_files > set->valid_files ?
"less valid files" :
"lower version");
190 while (*prev != duplicate) prev = &(*prev)->next;
193 set->next = duplicate->next;
200 DEBUG(grf, 1,
"Removing %s (%i) as base " SET_TYPE " set (duplicate, %s)", duplicate->name, duplicate->version,
201 duplicate->valid_files < set->valid_files ?
"less valid files" :
"lower version");
208 while (*last != NULL) last = &(*last)->next;
214 DEBUG(grf, 1,
"Adding %s (%i) as base " SET_TYPE " set", set->name, set->version);
230 template <
class Tbase_set>
242 if (strcmp(name, s->name) == 0) {
257 template <
class Tbase_set>
262 p +=
seprintf(p, last,
"%18s: %s", s->name, s->GetDescription());
263 int invalid = s->GetNumInvalid();
265 int missing = s->GetNumMissing();
267 p +=
seprintf(p, last,
" (%i corrupt file%s)\n", invalid, invalid == 1 ?
"" :
"s");
269 p +=
seprintf(p, last,
" (unusable: %i missing file%s)\n", missing, missing == 1 ?
"" :
"s");
280 #if defined(ENABLE_NETWORK) 285 for (; s != NULL; s = s->next) {
286 if (s->GetNumMissing() != 0)
continue;
288 if (s->shortname != ci->
unique_id)
continue;
289 if (!md5sum)
return s->files[0].filename;
292 memset(md5, 0,
sizeof(md5));
293 for (uint i = 0; i < Tbase_set::NUM_FILES; i++) {
294 for (uint j = 0; j <
sizeof(md5); j++) {
295 md5[j] ^= s->files[i].hash[j];
298 if (memcmp(md5, ci->
md5sum,
sizeof(md5)) == 0)
return s->files[0].filename;
303 template <
class Tbase_set>
312 template <
class Tbase_set>
318 template <
class Tbase_set>
330 template <
class Tbase_set>
345 template <
class Tbase_set>
351 if (s->GetNumMissing() != 0)
continue;
361 template <
class Tbase_set>
366 if (index == 0)
return s;
369 error(
"Base" SET_TYPE "::GetSet(): index %d out of range", index);
376 template <
class Tbase_set>
386 template <
class Tbase_set>
397 #define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \ 398 template const char *repl_type::ini_set; \ 399 template const char *repl_type::GetExtension(); \ 400 template bool repl_type::AddFile(const char *filename, size_t pathlength, const char *tar_filename); \ 401 template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ 402 template bool repl_type::SetSet(const char *name); \ 403 template char *repl_type::GetSetsList(char *p, const char *last); \ 404 template int repl_type::GetNumSets(); \ 405 template int repl_type::GetIndexOfUsedSet(); \ 406 template const set_type *repl_type::GetSet(int index); \ 407 template const set_type *repl_type::GetUsedSet(); \ 408 template bool repl_type::DetermineBestSet(); \ 409 template set_type *repl_type::GetAvailableSets(); \ 410 template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const set_type *s); A group within an ini file.
char *CDECL str_fmt(const char *str,...)
Format, "printf", into a newly allocated string.
uint32 unique_id
Unique ID; either GRF ID or shortname.
ChecksumResult check_result
cached result of md5 check
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Structure holding filename and MD5 information about a single file.
Functions related to debugging.
IniItem * item
the first item in the group
#define SET_TYPE
The type of set we're replacing.
void CheckExternalFiles()
Checks whether the MD5 checksums of the files are correct.
IniGroup * GetGroup(const char *name, size_t len=0, bool create_new=true)
Get the group with the given name.
Subdirectory for all base data (base sets, intro game)
IniItem * next
The next item in this group.
The file did exist, just the md5 checksum did not match.
A single "line" in an ini file.
const char * missing_warning
warning when this file is missing
Functions related to low-level strings.
const char * filename
filename
void LoadFromDisk(const char *filename, Subdirectory subdir)
Load the Ini file's data from the disk.
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
char * value
The value of this item.
Part of the network protocol handling content distribution.
Types related to reading/writing '*.ini' files.
byte md5sum[16]
The MD5 checksum.
#define DEBUG(name, level,...)
Output a line of debugging information.
Ini file that supports both loading and saving.
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
The file did exist and the md5 checksum did match.
char * name
The name of this item.
bool FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename=true)
Read the set information from a loaded ini.
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
IniItem * GetItem(const char *name, bool create)
Get the item with the given name, and if it doesn't exist and create is true it creates a new item...
Information about a single base set.
The file has not been checked yet.
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Container for all important information about a piece of content.
uint8 hash[16]
md5 sum of the file