mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-24 18:56:33 +00:00
dca237598b
svn-id: r24181
196 lines
5.4 KiB
C++
196 lines
5.4 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2004-2006 The ScummVM project
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "common/stdafx.h"
|
|
|
|
#include "common/util.h"
|
|
#include "common/hash-str.h"
|
|
#include "common/file.h"
|
|
#include "common/md5.h"
|
|
#include "common/advancedDetector.h"
|
|
|
|
namespace Common {
|
|
|
|
AdvancedDetector::AdvancedDetector() {
|
|
_fileMD5Bytes = 0;
|
|
}
|
|
|
|
String AdvancedDetector::getDescription(int num) {
|
|
char tmp[256];
|
|
ADGameDescription *g = _gameDescriptions[num];
|
|
|
|
snprintf(tmp, 256, "%s (%s %s/%s)", g->name, g->extra,
|
|
getPlatformDescription(g->platform), getLanguageDescription(g->language));
|
|
|
|
return String(tmp);
|
|
}
|
|
|
|
ADList AdvancedDetector::detectGame(const FSList *fslist, Language language, Platform platform) {
|
|
int filesCount;
|
|
|
|
typedef HashMap<String, bool, CaseSensitiveString_Hash, CaseSensitiveString_EqualTo> StringSet;
|
|
StringSet filesList;
|
|
|
|
typedef StringMap StringMap;
|
|
StringMap filesMD5;
|
|
|
|
String tstr, tstr2;
|
|
|
|
uint i;
|
|
int j;
|
|
char md5str[32+1];
|
|
uint8 md5sum[16];
|
|
int *matched;
|
|
|
|
uint matchedCount = 0;
|
|
bool fileMissing;
|
|
const ADGameFileDescription *fileDesc;
|
|
|
|
assert(_gameDescriptions.size());
|
|
|
|
matched = (int *)malloc(_gameDescriptions.size() * sizeof(int));
|
|
|
|
// First we compose list of files which we need MD5s for
|
|
for (i = 0; i < _gameDescriptions.size(); i++) {
|
|
for (j = 0; j < _gameDescriptions[i]->filesCount; j++) {
|
|
tstr = String(_gameDescriptions[i]->filesDescriptions[j].fileName);
|
|
tstr.toLowercase();
|
|
tstr2 = tstr + ".";
|
|
filesList[tstr] = true;
|
|
filesList[tstr2] = true;
|
|
}
|
|
}
|
|
|
|
if (fslist != NULL) {
|
|
for (FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) {
|
|
if (file->isDirectory()) continue;
|
|
tstr = file->name();
|
|
tstr.toLowercase();
|
|
tstr2 = tstr + ".";
|
|
|
|
if (!filesList.contains(tstr) && !filesList.contains(tstr2)) continue;
|
|
|
|
if (!md5_file(*file, md5sum, _fileMD5Bytes)) continue;
|
|
for (j = 0; j < 16; j++) {
|
|
sprintf(md5str + j*2, "%02x", (int)md5sum[j]);
|
|
}
|
|
filesMD5[tstr] = String(md5str);
|
|
filesMD5[tstr2] = String(md5str);
|
|
}
|
|
} else {
|
|
File testFile;
|
|
|
|
for (StringSet::const_iterator file = filesList.begin(); file != filesList.end(); ++file) {
|
|
tstr = file->_key;
|
|
tstr.toLowercase();
|
|
|
|
debug(3, "+ %s", tstr.c_str());
|
|
if (!filesMD5.contains(tstr)) {
|
|
if (testFile.open(file->_key)) {
|
|
testFile.close();
|
|
|
|
if (md5_file(file->_key.c_str(), md5sum, _fileMD5Bytes)) {
|
|
for (j = 0; j < 16; j++) {
|
|
sprintf(md5str + j*2, "%02x", (int)md5sum[j]);
|
|
}
|
|
filesMD5[tstr] = String(md5str);
|
|
debug(3, "> %s: %s", tstr.c_str(), md5str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < _gameDescriptions.size(); i++) {
|
|
filesCount = _gameDescriptions[i]->filesCount;
|
|
fileMissing = false;
|
|
|
|
// Try to open all files for this game
|
|
for (j = 0; j < filesCount; j++) {
|
|
fileDesc = &_gameDescriptions[i]->filesDescriptions[j];
|
|
tstr = fileDesc->fileName;
|
|
tstr.toLowercase();
|
|
tstr2 = tstr + ".";
|
|
|
|
if (!filesMD5.contains(tstr) && !filesMD5.contains(tstr2)) {
|
|
fileMissing = true;
|
|
break;
|
|
}
|
|
if (strcmp(fileDesc->md5, filesMD5[tstr].c_str()) && strcmp(fileDesc->md5, filesMD5[tstr2].c_str())) {
|
|
fileMissing = true;
|
|
break;
|
|
} else {
|
|
debug(3, "Matched file: %s", tstr.c_str());
|
|
}
|
|
}
|
|
if (!fileMissing) {
|
|
debug(2, "Found game: %s", getDescription(i).c_str());
|
|
matched[matchedCount++] = i;
|
|
}
|
|
}
|
|
|
|
if (!filesMD5.empty() && (matchedCount == 0)) {
|
|
printf("MD5s of your game version are unknown. Please, report following data to\n");
|
|
printf("ScummVM team along with your game name and version:\n");
|
|
|
|
for (StringMap::const_iterator file = filesMD5.begin(); file != filesMD5.end(); ++file)
|
|
printf("%s: %s\n", file->_key.c_str(), file->_value.c_str());
|
|
}
|
|
|
|
// We have some resource sets which are superpositions of other
|
|
// Now remove lesser set if bigger matches too
|
|
|
|
if (matchedCount > 1) {
|
|
// Search max number
|
|
int maxcount = 0;
|
|
for (i = 0; i < matchedCount; i++) {
|
|
maxcount = MAX(_gameDescriptions[matched[i]]->filesCount, maxcount);
|
|
}
|
|
|
|
// Now purge targets with number of files lesser than max
|
|
for (i = 0; i < matchedCount; i++) {
|
|
if ((_gameDescriptions[matched[i]]->language != language && language != UNK_LANG) ||
|
|
(_gameDescriptions[matched[i]]->platform != platform && platform != kPlatformUnknown)) {
|
|
debug(2, "Purged %s", getDescription(matched[i]).c_str());
|
|
matched[i] = -1;
|
|
continue;
|
|
}
|
|
|
|
if (_gameDescriptions[matched[i]]->filesCount < maxcount) {
|
|
debug(2, "Purged: %s", getDescription(matched[i]).c_str());
|
|
matched[i] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ADList *returnMatches = new ADList;
|
|
j = 0;
|
|
for (i = 0; i < matchedCount; i++)
|
|
if (matched[i] != -1)
|
|
returnMatches->push_back(matched[i]);
|
|
|
|
return *returnMatches;
|
|
}
|
|
|
|
} // End of namespace Common
|