00001 /* 00002 Copyright (C) 2003-2005 The Pentagram team 00003 00004 This program is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU General Public License 00006 as published by the Free Software Foundation; either version 2 00007 of the License, or (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 */ 00018 00019 #include "pent_include.h" 00020 00021 #include "GameDetector.h" 00022 #include "FileSystem.h" 00023 #include "GameInfo.h" 00024 #include "RawArchive.h" 00025 #include "md5.h" 00026 00027 #include "gamemd5.h" 00028 00029 bool GameDetector::detect(std::string path, GameInfo *info) 00030 { 00031 FileSystem* fs = FileSystem::get_instance(); 00032 if (!fs->AddVirtualPath("@detect", path)) 00033 return false; 00034 00035 IDataSource* ids; 00036 00037 00038 // Strategy: find eusecode.flx, fusecode.flx or gusecode.flx, 00039 // compute its MD5, and check it against our MD5 table. 00040 // Should that fail, try a manual check to at least identify the 00041 // game type and its language. 00042 00043 ids = fs->ReadFile("@detect/usecode/eusecode.flx"); 00044 if (!ids) 00045 ids = fs->ReadFile("@detect/usecode/fusecode.flx"); 00046 if (!ids) 00047 ids = fs->ReadFile("@detect/usecode/gusecode.flx"); 00048 if (!ids) 00049 ids = fs->ReadFile("@detect/usecode/jusecode.flx"); 00050 if (!ids) 00051 return false; // all games have usecode 00052 00053 Pentagram::md5_file(ids, info->md5, 0); 00054 delete ids; 00055 00056 std::string md5s = info->getPrintableMD5(); 00057 00058 int i = 0; 00059 while (Pentagram::md5table[i].md5) { 00060 if (md5s == Pentagram::md5table[i].md5) { 00061 info->type = Pentagram::md5table[i].type; 00062 info->language = Pentagram::md5table[i].language; 00063 info->version = Pentagram::md5table[i].version; 00064 return true; 00065 } 00066 i++; 00067 } 00068 00069 perr << "MD5-based game autodetection failed (" << md5s << "). " 00070 << std::endl << "Trying manual detection." << std::endl; 00071 00072 00073 00074 // game type 00075 if (info->type == GameInfo::GAME_UNKNOWN) { 00076 00077 ids = fs->ReadFile("@detect/static/u8gumps.flx"); // random U8 file 00078 if (ids) { 00079 info->type = GameInfo::GAME_U8; 00080 delete ids; ids = 0; 00081 } 00082 00083 } 00084 00085 if (info->type == GameInfo::GAME_UNKNOWN) { 00086 00087 ids = fs->ReadFile("@detect/static/help1.dat"); // random remorse file 00088 if (ids) { 00089 info->type = GameInfo::GAME_REMORSE; 00090 delete ids; ids = 0; 00091 } 00092 00093 } 00094 00095 if (info->type == GameInfo::GAME_UNKNOWN) { 00096 00097 ids = fs->ReadFile("@detect/static/help1.bmp"); // random regret file 00098 if (ids) { 00099 info->type = GameInfo::GAME_REGRET; 00100 delete ids; ids = 0; 00101 } 00102 00103 } 00104 00105 //TODO: game version 00106 info->version = 999; 00107 00108 00109 // game language 00110 00111 // detect using eusecode/fusecode/gusecode 00112 if (info->language == GameInfo::GAMELANG_UNKNOWN) { 00113 ids = fs->ReadFile("@detect/usecode/eusecode.flx"); 00114 if (ids) { 00115 if (info->type == GameInfo::GAME_U8) { 00116 // distinguish between english and spanish 00117 RawArchive* f = new RawArchive(ids); 00118 const char* buf = reinterpret_cast<const char*>((f->get_object_nodel(183))); 00119 unsigned int size = f->get_size(183); 00120 if (buf) { 00121 for (unsigned int i = 0; i + 9 < size; ++i) { 00122 if (strncmp(buf+i, "tableware", 9) == 0) { 00123 info->language = GameInfo::GAMELANG_ENGLISH; 00124 break; 00125 } 00126 if (strncmp(buf+i, "vajilla", 7) == 0) { 00127 info->language = GameInfo::GAMELANG_SPANISH; 00128 break; 00129 } 00130 } 00131 } 00132 delete f; ids = 0; // ids is deleted when f is deleted 00133 } 00134 00135 // if still unsure, English 00136 if (info->language == GameInfo::GAMELANG_UNKNOWN) 00137 info->language = GameInfo::GAMELANG_ENGLISH; 00138 00139 delete ids; ids = 0; 00140 } 00141 } 00142 if (info->language == GameInfo::GAMELANG_UNKNOWN) { 00143 ids = fs->ReadFile("@detect/usecode/fusecode.flx"); 00144 if (ids) { 00145 info->language = GameInfo::GAMELANG_FRENCH; 00146 delete ids; ids = 0; 00147 } 00148 } 00149 if (info->language == GameInfo::GAMELANG_UNKNOWN) { 00150 ids = fs->ReadFile("@detect/usecode/gusecode.flx"); 00151 if (ids) { 00152 info->language = GameInfo::GAMELANG_GERMAN; 00153 delete ids; ids = 0; 00154 } 00155 } 00156 if (info->language == GameInfo::GAMELANG_UNKNOWN) { 00157 ids = fs->ReadFile("@detect/usecode/jusecode.flx"); 00158 if (ids) { 00159 info->language = GameInfo::GAMELANG_JAPANESE; 00160 delete ids; ids = 0; 00161 } 00162 } 00163 00164 fs->RemoveVirtualPath("@detect"); 00165 00166 return (info->type != GameInfo::GAME_UNKNOWN && 00167 /* info->version != 0 && */ 00168 info->language != GameInfo::GAMELANG_UNKNOWN); 00169 }