(svn r17241) -Change: make a distinction between missing and corrupted data files. If (at least) one data file is missing do not consider the set to be useable. Do also no autodetect sets with missing files.

replace/41b28d7194a279bdc17475d4fbe2ea6ec885a466
rubidium 15 years ago
parent 367ff2375a
commit 2fd1b000e5

@ -5,7 +5,7 @@
;
[metadata]
name = original_dos
shortname = TTDD
shortname = TTDO
version = 0
description = Original Transport Tycoon Deluxe DOS edition sounds

@ -5,7 +5,7 @@
;
[metadata]
name = original_windows
shortname = TTDW
shortname = TTDO
version = 0
description = Original Transport Tycoon Deluxe Windows edition sounds

@ -13,11 +13,18 @@ struct ContentInfo;
/** Structure holding filename and MD5 information about a single file */
struct MD5File {
/** The result of a checksum check */
enum ChecksumResult {
CR_MATCH, ///< The file did exist and the md5 checksum did match
CR_MISMATCH, ///< The file did exist, just the md5 checksum did not match
CR_NO_FILE, ///< The file did not exist
};
const char *filename; ///< filename
uint8 hash[16]; ///< md5 sum of the file
const char *missing_warning; ///< warning when this file is missing
bool CheckMD5() const;
ChecksumResult CheckMD5() const;
};
/**
@ -40,6 +47,7 @@ struct BaseSet {
MD5File files[NUM_FILES]; ///< All files part of this set
uint found_files; ///< Number of the files that could be found
uint valid_files; ///< Number of the files that could be found and are valid
T *next; ///< The next base set in this list
@ -65,6 +73,16 @@ struct BaseSet {
return Tnum_files - this->found_files;
}
/**
* Get the number of invalid files.
* @note a missing file is invalid too!
* @return the number
*/
int GetNumInvalid() const
{
return Tnum_files - this->valid_files;
}
/**
* Read the set information from a loaded ini.
* @param ini the ini to read from
@ -172,16 +190,6 @@ enum GraphicsFileType {
struct GraphicsSet : BaseSet<GraphicsSet, MAX_GFT> {
PaletteType palette; ///< Palette of this graphics set
/**
* Is this set useable? Are enough files found to think it exists.
* @return true if it's useable.
*/
bool IsUseable() const
{
/* Do not find 'only' openttd[dw].grf */
return this->found_files > 1;
}
bool FillSetDetails(struct IniFile *ini, const char *path);
};
@ -196,14 +204,6 @@ public:
/** All data of a sounds set. */
struct SoundsSet : BaseSet<SoundsSet, 1> {
/**
* Is this set useable? Are enough files found to think it exists.
* @return true if it's useable.
*/
bool IsUseable() const
{
return this->found_files > 0;
}
};
/** All data/functions related with replacing the base sounds */

@ -95,7 +95,17 @@ bool BaseSet<T, Tnum_files>::FillSetDetails(IniFile *ini, const char *path)
file->missing_warning = strdup(item->value);
}
if (file->CheckMD5()) this->found_files++;
switch (file->CheckMD5()) {
case MD5File::CR_MATCH:
this->valid_files++;
/* FALL THROUGH */
case MD5File::CR_MISMATCH:
this->found_files++;
break;
case MD5File::CR_NO_FILE:
break;
}
}
return true;
@ -129,8 +139,8 @@ bool BaseMedia<Tbase_set>::AddFile(const char *filename, size_t basepath_length)
}
if (duplicate != NULL) {
/* The more complete set takes precedence over the version number. */
if ((duplicate->found_files == set->found_files && duplicate->version >= set->version) ||
duplicate->found_files > set->found_files) {
if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) ||
duplicate->valid_files > set->valid_files) {
DEBUG(grf, 1, "Not adding %s (%i) as base " SET_TYPE " set (duplicate)", set->name, set->version);
delete set;
} else {
@ -191,12 +201,15 @@ template <class Tbase_set>
{
p += seprintf(p, last, "List of " SET_TYPE " sets:\n");
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != NULL; s = s->next) {
if (!s->IsUseable()) continue;
p += seprintf(p, last, "%18s: %s", s->name, s->description);
int missing = s->GetNumMissing();
if (missing != 0) {
p += seprintf(p, last, " (missing %i file%s)\n", missing, missing == 1 ? "" : "s");
int invalid = s->GetNumInvalid();
if (invalid != 0) {
int missing = s->GetNumMissing();
if (missing == 0) {
p += seprintf(p, last, " (%i corrupt file%s)\n", invalid, invalid == 1 ? "" : "s");
} else {
p += seprintf(p, last, " (unuseable: %i missing file%s)\n", missing, missing == 1 ? "" : "s");
}
} else {
p += seprintf(p, last, "\n");
}
@ -213,7 +226,7 @@ template <class Tbase_set>
/* static */ bool BaseMedia<Tbase_set>::HasSet(const ContentInfo *ci, bool md5sum)
{
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != NULL; s = s->next) {
if (!s->IsUseable()) continue;
if (s->GetNumMissing() != 0) continue;
if (s->shortname != ci->unique_id) continue;
if (!md5sum) return true;
@ -246,7 +259,7 @@ template <class Tbase_set>
{
int n = 0;
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != NULL; s = s->next) {
if (s != BaseMedia<Tbase_set>::used_set && !s->IsUseable()) continue;
if (s != BaseMedia<Tbase_set>::used_set && s->GetNumMissing() != 0) continue;
n++;
}
return n;
@ -258,7 +271,7 @@ template <class Tbase_set>
int n = 0;
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != NULL; s = s->next) {
if (s == BaseMedia<Tbase_set>::used_set) return n;
if (!s->IsUseable()) continue;
if (s->GetNumMissing() != 0) continue;
n++;
}
return -1;
@ -268,7 +281,7 @@ template <class Tbase_set>
/* static */ const Tbase_set *BaseMedia<Tbase_set>::GetSet(int index)
{
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != NULL; s = s->next) {
if (s != BaseMedia<Tbase_set>::used_set && !s->IsUseable()) continue;
if (s != BaseMedia<Tbase_set>::used_set && s->GetNumMissing() != 0) continue;
if (index == 0) return s;
index--;
}

@ -85,7 +85,6 @@ static void LoadGrfIndexed(const char *filename, const SpriteID *index_tbl, int
LoadSpritesIndexed(file_index, &sprite_id, index_tbl);
}
/**
* Checks whether the MD5 checksums of the files are correct.
*
@ -111,25 +110,24 @@ void CheckExternalFiles()
char *add_pos = error_msg;
const char *last = lastof(error_msg);
if (used_set->GetNumMissing() != 0) {
if (used_set->GetNumInvalid() != 0) {
/* Not all files were loaded succesfully, see which ones */
add_pos += seprintf(add_pos, last, "Trying to load graphics set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one.\n\nThe following files are corrupted or missing:\n", used_set->name);
for (uint i = 0; i < GraphicsSet::NUM_FILES; i++) {
if (!used_set->files[i].CheckMD5()) {
add_pos += seprintf(add_pos, last, "\t%s (%s)\n", used_set->files[i].filename, used_set->files[i].missing_warning);
}
MD5File::ChecksumResult res = used_set->files[i].CheckMD5();
if (res != MD5File::CR_MATCH) add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", used_set->files[i].filename, res == MD5File::CR_MISMATCH ? "corrupt" : "missing", used_set->files[i].missing_warning);
}
add_pos += seprintf(add_pos, last, "\n");
}
const SoundsSet *sounds_set = BaseSounds::GetUsedSet();
if (sounds_set->GetNumMissing() != 0) {
if (sounds_set->GetNumInvalid() != 0) {
add_pos += seprintf(add_pos, last, "Trying to load sound set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one.\n\nThe following files are corrupted or missing:\n", sounds_set->name);
assert_compile(SoundsSet::NUM_FILES == 1);
/* No need to loop each file, as long as there is only a single
* sound file. */
add_pos += seprintf(add_pos, last, "\t%s (%s)\n", sounds_set->files->filename, sounds_set->files->missing_warning);
add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", sounds_set->files->filename, sounds_set->files->CheckMD5() == MD5File::CR_MISMATCH ? "corrupt" : "missing", sounds_set->files->missing_warning);
}
if (add_pos != error_msg) ShowInfoF("%s", error_msg);
@ -218,31 +216,32 @@ bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path)
/**
* Calculate and check the MD5 hash of the supplied filename.
* @return true if the checksum is correct.
* @return
* CR_MATCH if the MD5 hash matches
* CR_MISMATCH if the MD5 does not match
* CR_NO_FILE if the file misses
*/
bool MD5File::CheckMD5() const
MD5File::ChecksumResult MD5File::CheckMD5() const
{
size_t size;
FILE *f = FioFOpenFile(this->filename, "rb", DATA_DIR, &size);
if (f != NULL) {
Md5 checksum;
uint8 buffer[1024];
uint8 digest[16];
size_t len;
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
size -= len;
checksum.Append(buffer, len);
}
if (f == NULL) return CR_NO_FILE;
FioFCloseFile(f);
Md5 checksum;
uint8 buffer[1024];
uint8 digest[16];
size_t len;
checksum.Finish(digest);
return memcmp(this->hash, digest, sizeof(this->hash)) == 0;
} else { // file not found
return false;
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
size -= len;
checksum.Append(buffer, len);
}
FioFCloseFile(f);
checksum.Finish(digest);
return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH;
}
/** Names corresponding to the GraphicsFileType */
@ -287,10 +286,14 @@ template <class Tbase_set>
{
if (BaseMedia<Tbase_set>::used_set != NULL) return true;
const Tbase_set *best = BaseMedia<Tbase_set>::available_sets;
const Tbase_set *best = NULL;
for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
if (best->found_files < c->found_files ||
(best->found_files == c->found_files && (
/* Skip unuseable sets */
if (c->GetNumMissing() != 0) continue;
if (best == NULL ||
best->valid_files < c->valid_files ||
(best->valid_files == c->valid_files && (
(best->shortname == c->shortname && best->version < c->version) ||
(best->palette != _use_palette && c->palette == _use_palette)))) {
best = c;

@ -199,7 +199,7 @@ struct GameOptionsWindow : Window {
case GOW_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break;
case GOW_SCREENSHOT_DROPDOWN: SetDParam(0, SPECSTR_SCREENSHOT_START + _cur_screenshot_format); break;
case GOW_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break;
case GOW_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumMissing()); break;
case GOW_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break;
case GOW_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break;
}
}
@ -238,10 +238,10 @@ struct GameOptionsWindow : Window {
case GOW_BASE_GRF_STATUS:
/* Find the biggest description for the default size. */
for (int i = 0; i < BaseGraphics::GetNumSets(); i++) {
uint missing_files = BaseGraphics::GetSet(i)->GetNumMissing();
if (missing_files == 0) continue;
uint invalid_files = BaseGraphics::GetSet(i)->GetNumInvalid();
if (invalid_files == 0) continue;
SetDParam(0, missing_files);
SetDParam(0, invalid_files);
*size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_GRF_STATUS));
}
break;

@ -281,10 +281,14 @@ template <class Tbase_set>
{
if (BaseMedia<Tbase_set>::used_set != NULL) return true;
const Tbase_set *best = BaseMedia<Tbase_set>::available_sets;
const Tbase_set *best = NULL;
for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
if (best->found_files < c->found_files ||
(best->found_files == c->found_files &&
/* Skip unuseable sets */
if (c->GetNumMissing() != 0) continue;
if (best == NULL ||
best->valid_files < c->valid_files ||
(best->valid_files == c->valid_files &&
(best->shortname == c->shortname && best->version < c->version))) {
best = c;
}

Loading…
Cancel
Save