OpenTTD Source
1.11.0-beta2
|
Go to the documentation of this file.
22 #define fetch_metadata(name) \
23 item = metadata->GetItem(name, false); \
24 if (item == nullptr || !item->value.has_value() || item->value->empty()) { \
25 DEBUG(grf, 0, "Base " SET_TYPE "set detail loading: %s field missing.", name); \
26 DEBUG(grf, 0, " Is %s readable for the user running OpenTTD?", full_filename); \
38 template <
class T,
size_t Tnum_files,
bool Tsearch_in_tars>
45 this->name = *item->
value;
48 this->description[std::string{}] = *item->
value;
51 for (
const IniItem *item = metadata->
item; item !=
nullptr; item = item->
next) {
52 if (item->
name.compare(0, 12,
"description.") != 0)
continue;
54 this->description[item->
name.substr(12)] = item->
value.value_or(
"");
58 for (uint i = 0; (*item->
value)[i] !=
'\0' && i < 4; i++) {
59 this->shortname |= ((uint8)(*item->
value)[i]) << (i * 8);
63 this->version = atoi(item->
value->c_str());
65 item = metadata->
GetItem(
"fallback",
false);
66 this->fallback = (item !=
nullptr && item->
value && *item->
value !=
"0" && *item->
value !=
"false");
72 for (uint i = 0; i < Tnum_files; i++) {
73 MD5File *file = &this->files[i];
76 if (item ==
nullptr || (!item->
value.has_value() && !allow_empty_filename)) {
81 if (!item->
value.has_value()) {
89 const char *filename = item->
value->c_str();
93 item = md5s->
GetItem(filename,
false);
94 if (item ==
nullptr || !item->
value.has_value()) {
95 DEBUG(grf, 0,
"No MD5 checksum specified for: %s (in %s)", filename, full_filename);
98 const char *c = item->
value->c_str();
99 for (uint i = 0; i <
sizeof(file->
hash) * 2; i++, c++) {
101 if (
'0' <= *c && *c <=
'9') {
103 }
else if (
'a' <= *c && *c <=
'f') {
105 }
else if (
'A' <= *c && *c <=
'F') {
108 DEBUG(grf, 0,
"Malformed MD5 checksum specified for: %s (in %s)", filename, full_filename);
112 file->
hash[i / 2] = j << 4;
114 file->
hash[i / 2] |= j;
119 item = origin->
GetItem(filename,
false);
120 if (item ==
nullptr) item = origin->
GetItem(
"default",
false);
121 if (item ==
nullptr || !item->
value.has_value()) {
122 DEBUG(grf, 1,
"No origin warning message specified for: %s", filename);
139 DEBUG(grf, 1,
"MD5 checksum mismatch for: %s (in %s)", filename, full_filename);
144 DEBUG(grf, 1,
"The file %s specified in %s is missing", filename, full_filename);
152 template <
class Tbase_set>
156 DEBUG(grf, 1,
"Checking %s for base " SET_TYPE " set", filename.c_str());
158 Tbase_set *set =
new Tbase_set();
160 std::string path{ filename, basepath_length };
163 auto psep = path.rfind(PATHSEPCHAR);
164 if (psep != std::string::npos) {
165 path.erase(psep + 1);
170 if (set->FillSetDetails(ini, path.c_str(), filename.c_str())) {
171 Tbase_set *duplicate =
nullptr;
173 if (c->name == set->name || c->shortname == set->shortname) {
178 if (duplicate !=
nullptr) {
180 if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) ||
181 duplicate->valid_files > set->valid_files) {
182 DEBUG(grf, 1,
"Not adding %s (%i) as base " SET_TYPE " set (duplicate, %s)", set->name.c_str(), set->version,
183 duplicate->valid_files > set->valid_files ?
"less valid files" :
"lower version");
188 while (*prev != duplicate) prev = &(*prev)->next;
191 set->next = duplicate->next;
198 DEBUG(grf, 1,
"Removing %s (%i) as base " SET_TYPE " set (duplicate, %s)", duplicate->name.c_str(), duplicate->version,
199 duplicate->valid_files < set->valid_files ?
"less valid files" :
"lower version");
206 while (*last !=
nullptr) last = &(*last)->next;
212 DEBUG(grf, 1,
"Adding %s (%i) as base " SET_TYPE " set", set->name.c_str(), set->version);
227 template <
class Tbase_set>
239 if (name == s->name) {
254 template <
class Tbase_set>
259 p +=
seprintf(p, last,
"%18s: %s", s->name.c_str(), s->GetDescription({}));
260 int invalid = s->GetNumInvalid();
262 int missing = s->GetNumMissing();
264 p +=
seprintf(p, last,
" (%i corrupt file%s)\n", invalid, invalid == 1 ?
"" :
"s");
266 p +=
seprintf(p, last,
" (unusable: %i missing file%s)\n", missing, missing == 1 ?
"" :
"s");
281 for (; s !=
nullptr; s = s->next) {
282 if (s->GetNumMissing() != 0)
continue;
284 if (s->shortname != ci->
unique_id)
continue;
285 if (!md5sum)
return s->files[0].filename;
288 memset(md5, 0,
sizeof(md5));
289 for (uint i = 0; i < Tbase_set::NUM_FILES; i++) {
290 for (uint j = 0; j <
sizeof(md5); j++) {
291 md5[j] ^= s->files[i].hash[j];
294 if (memcmp(md5, ci->
md5sum,
sizeof(md5)) == 0)
return s->files[0].filename;
299 template <
class Tbase_set>
310 template <
class Tbase_set>
325 template <
class Tbase_set>
331 if (s->GetNumMissing() != 0)
continue;
341 template <
class Tbase_set>
346 if (index == 0)
return s;
349 error(
"Base" SET_TYPE "::GetSet(): index %d out of range", index);
356 template <
class Tbase_set>
366 template <
class Tbase_set>
377 #define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \
378 template std::string repl_type::ini_set; \
379 template const char *repl_type::GetExtension(); \
380 template bool repl_type::AddFile(const std::string &filename, size_t pathlength, const std::string &tar_filename); \
381 template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \
382 template bool repl_type::SetSet(const std::string &name); \
383 template char *repl_type::GetSetsList(char *p, const char *last); \
384 template int repl_type::GetNumSets(); \
385 template int repl_type::GetIndexOfUsedSet(); \
386 template const set_type *repl_type::GetSet(int index); \
387 template const set_type *repl_type::GetUsedSet(); \
388 template bool repl_type::DetermineBestSet(); \
389 template set_type *repl_type::GetAvailableSets(); \
390 template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const set_type *s);
IniItem * next
The next item in this group.
@ CR_MISMATCH
The file did exist, just the md5 checksum did not match.
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
A single "line" in an ini file.
A group within an ini file.
ChecksumResult check_result
cached result of md5 check
#define SET_TYPE
The type of set we're replacing.
@ CR_MATCH
The file did exist and the md5 checksum did match.
const char * missing_warning
warning when this file is missing
uint8 hash[16]
md5 sum of the file
#define DEBUG(name, level,...)
Output a line of debugging information.
std::optional< std::string > value
The value of this item.
Container for all important information about a piece of content.
byte md5sum[16]
The MD5 checksum.
void CheckExternalFiles()
Checks whether the MD5 checksums of the files are correct.
Ini file that supports both loading and saving.
Structure holding filename and MD5 information about a single file.
char *CDECL str_fmt(const char *str,...)
Format, "printf", into a newly allocated string.
Information about a single base set.
@ CR_NO_FILE
The file did not exist.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
@ CR_UNKNOWN
The file has not been checked yet.
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
const char * filename
filename
uint32 unique_id
Unique ID; either GRF ID or shortname.
std::string name
The name of this item.
IniItem * item
the first item in the group
IniItem * GetItem(const std::string &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.
void LoadFromDisk(const std::string &filename, Subdirectory subdir)
Load the Ini file's data from the disk.
bool FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename=true)
Read the set information from a loaded ini.
IniGroup * GetGroup(const std::string &name, bool create_new=true)
Get the group with the given name.