ScummVM API documentation
advancedDetector.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef ENGINES_ADVANCED_DETECTOR_H
23#define ENGINES_ADVANCED_DETECTOR_H
24
25#include "engines/metaengine.h"
26#include "engines/engine.h"
27
28#include "common/hash-str.h"
29
30#include "common/gui_options.h" // Keep it here, so detection tables can refer to them
31
32namespace Common {
33class Error;
34class FSList;
35}
45/* Some helpers functions to avoid code duplication */
46namespace ADDynamicDescription {
47
48static inline uint32 strSizeBuffer(const char * const &field) {
49 return field ? (uint32)strlen(field) + 1 : 0;
50}
51static inline void *strToBuffer(void *buffer, const char *&field) {
52 if (field) {
53 int len = (int)strlen(field) + 1;
54 memcpy((char *)buffer, field, len);
55 field = (const char *)buffer;
56 buffer = (char *)buffer + len;
57 }
58 return buffer;
59}
60
61static inline uint32 alignSizeBuffer() {
62 // We consider alignments up to pointer size
63 return sizeof(void *) - 1;
64}
65static inline void *alignToBuffer(void *buffer) {
66 // Round up
67 uintptr tmp = (uintptr)buffer + sizeof(void *) - 1;
68 return (void *)(tmp & -(int)sizeof(void *));
69}
70
71} // End of namespace ADDynamicDescription
72
79 const char *fileName;
80 uint16 fileType;
81 const char *md5;
82 uint32 fileSize;
83
84 uint32 sizeBuffer() const {
85 uint32 ret = 0;
86 ret += ADDynamicDescription::strSizeBuffer(fileName);
87 ret += ADDynamicDescription::strSizeBuffer(md5);
88 return ret;
89 }
90
91 void *toBuffer(void *buffer) {
92 buffer = ADDynamicDescription::strToBuffer(buffer, fileName);
93 buffer = ADDynamicDescription::strToBuffer(buffer, md5);
94 return buffer;
95 }
96};
97
98#define AD_NO_SIZE ((uint32)-1)
99
104#define AD_LISTEND {NULL, 0, NULL, 0}
105
110#define AD_ENTRY1(f, x) {{ f, 0, x, AD_NO_SIZE}, AD_LISTEND}
111
116#define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, AD_LISTEND}
117
122#define AD_ENTRY2s(f1, x1, s1, f2, x2, s2) {{f1, 0, x1, s1}, {f2, 0, x2, s2}, AD_LISTEND}
123
128#define AD_ENTRY3s(f1, x1, s1, f2, x2, s2, f3, x3, s3) {{f1, 0, x1, s1}, {f2, 0, x2, s2}, {f3, 0, x3, s3}, AD_LISTEND}
129#define AD_ENTRY4s(f1, x1, s1, f2, x2, s2, f3, x3, s3, f4, x4, s4) {{f1, 0, x1, s1}, {f2, 0, x2, s2}, {f3, 0, x3, s3}, {f4, 0, x4, s4}, AD_LISTEND}
130#define AD_ENTRY5s(f1, x1, s1, f2, x2, s2, f3, x3, s3, f4, x4, s4, f5, x5, s5) {{f1, 0, x1, s1}, {f2, 0, x2, s2}, {f3, 0, x3, s3}, {f4, 0, x4, s4}, {f5, 0, x5, s5}, AD_LISTEND}
131#define AD_ENTRY6s(f1, x1, s1, f2, x2, s2, f3, x3, s3, f4, x4, s4, f5, x5, s5, f6, x6, s6) {{f1, 0, x1, s1}, {f2, 0, x2, s2}, {f3, 0, x3, s3}, {f4, 0, x4, s4}, {f5, 0, x5, s5}, {f6, 0, x6, s6}, AD_LISTEND}
132
138enum ADGameFlags : uint {
140 ADGF_ADDON = (1u << 15),
141 ADGF_TAILMD5 = (1u << 16),
142 ADGF_AUTOGENTARGET = (1u << 17),
143 ADGF_UNSTABLE = (1u << 18),
144 ADGF_TESTING = (1u << 19),
145 ADGF_PIRATED = (1u << 20),
146 ADGF_UNSUPPORTED = (1u << 21),
148 ADGF_WARNING = (1u << 22),
150 ADGF_ADDENGLISH = (1u << 23),
151 ADGF_MACRESFORK = (1u << 24),
152 ADGF_USEEXTRAASTITLE = (1u << 25),
153 ADGF_DROPLANGUAGE = (1u << 26),
154 ADGF_DROPPLATFORM = (1u << 27),
155 ADGF_CD = (1u << 28),
156 ADGF_DVD = (1u << 29),
157 ADGF_DEMO = (1u << 30),
158 ADGF_REMASTERED = (1u << 31)
160
170 const char *gameId;
171
181 const char *extra;
182
190
195
200
207 uint32 flags;
208
216 const char *guiOptions;
217
221 uint32 sizeBuffer() const {
222 uint32 ret = 0;
223 ret += ADDynamicDescription::strSizeBuffer(gameId);
224 ret += ADDynamicDescription::strSizeBuffer(extra);
225 for(int i = 0; i < ARRAYSIZE(filesDescriptions); i++) {
226 ret += filesDescriptions[i].sizeBuffer();
227 }
228 ret += ADDynamicDescription::strSizeBuffer(guiOptions);
229 return ret;
230 }
231
239 void *toBuffer(void *buffer) {
240 buffer = ADDynamicDescription::strToBuffer(buffer, gameId);
241 buffer = ADDynamicDescription::strToBuffer(buffer, extra);
242 for(int i = 0; i < ARRAYSIZE(filesDescriptions); i++) {
243 buffer = filesDescriptions[i].toBuffer(buffer);
244 }
245 buffer = ADDynamicDescription::strToBuffer(buffer, guiOptions);
246 return buffer;
247 }
248};
249
256#define AD_GAME_DESCRIPTION_HELPERS(field) \
257 uint32 sizeBuffer() const { \
258 return field.sizeBuffer(); \
259 } \
260 void *toBuffer(void *buffer) { \
261 return field.toBuffer(buffer); \
262 }
263
270template<class T>
271class ADDynamicGameDescription : public T {
272public:
273 ADDynamicGameDescription(const T *other) : _buffer(nullptr) {
274 // First copy all fields
275 memcpy(static_cast<T*>(this), other, sizeof(T));
276
277 // Then calculate the size of the dynamic buffer
278 // we will need to store evrything pointed at by
279 // the structures
280 uint32 sz = other->sizeBuffer();
281 _buffer = new byte[sz];
282
283 // Finally copy every pointer in the buffer
284 // and make the structure point into it
285 void *end = this->toBuffer(_buffer);
286 assert(end <= _buffer + sz);
287 (void)end;
288 }
289
291 delete[] _buffer;
292 }
293
294private:
295 byte *_buffer;
296};
297
304};
305
314 ADDetectedGame() : desc(nullptr), hasUnknownFiles(false) {}
318 explicit ADDetectedGame(const ADGameDescription *d) : desc(d), hasUnknownFiles(false) {}
319};
320
323
328#define AD_TABLE_END_MARKER \
329 { NULL, NULL, { { NULL, 0, NULL, 0 } }, Common::UNK_LANG, Common::kPlatformUnknown, ADGF_NO_FLAGS, GUIO0() }
330
337
342 const char *filenames[10];
343};
344
345
358
371
381
388
393};
394
395
401 const char *guioFlag;
403};
404
405#define AD_EXTRA_GUI_OPTIONS_TERMINATOR { 0, { 0, 0, 0, 0, 0, 0 } }
406
411protected:
419 const byte *_gameDescriptors;
420
426 const uint _descItemSize;
427
433
444
451 uint32 _flags;
452
460
467
476 const char * const *_directoryGlobs;
477
484
491
495 AdvancedMetaEngineDetectionBase(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds);
496
497public:
504
506 PlainGameDescriptor findGame(const char *gameId) const override;
507
509 Common::Error identifyGame(DetectedGame &game, const void **descriptor) override;
510
516 DetectedGames detectGames(const Common::FSList &fslist, uint32 skipADFlags, bool skipIncomplete) override;
517
518 uint getMD5Bytes() const override final { return _md5Bytes; }
519
520 int getGameVariantCount() const override final {
521 uint count = 0;
522 for (const byte *descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != nullptr; descPtr += _descItemSize)
523 ++count;
524 return count;
525 }
526
527 void dumpDetectionEntries() const override;
528
532 static Common::String sanitizeName(const char *name, int maxLen);
533
534protected:
539
544 virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra = nullptr) const {
545 return ADDetectedGame();
546 }
547
548private:
549 void preprocessDescriptions();
550 static Common::StringArray getPathsFromEntry(const ADGameDescription *g);
551 bool isEntryGrayListed(const ADGameDescription *g) const;
552 void detectClashes() const;
553
554private:
557 bool _hashMapsInited;
558
559protected:
576 virtual ADDetectedGames detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra, uint32 skipADFlags = 0, bool skipIncomplete = false);
577
589 ADDetectedGame detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const;
590
596 void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::Path &parentName = Common::Path()) const;
597
599 bool getFileProperties(const FileMap &allFiles, MD5Properties md5prop, const Common::Path &fname, FileProperties &fileProps) const;
600
602 virtual DetectedGame toDetectedGame(const ADDetectedGame &adGame, ADDetectedGameExtraInfo *extraInfo = nullptr) const;
603
605 bool cleanupPirated(ADDetectedGames &matched) const;
606
607 friend class FileMapArchive;
608};
609
610template<class Descriptor>
612protected:
613 AdvancedMetaEngineDetection(const Descriptor *descs, const PlainGameDescriptor *gameIds) : AdvancedMetaEngineDetectionBase(descs, sizeof(Descriptor), gameIds) {}
614
615 Common::Error identifyGame(DetectedGame &game, const void **descriptor) override {
616 assert(descriptor);
618 if (err.getCode() != Common::kNoError) {
619 return err;
620 }
621 if (*descriptor) {
622 *descriptor = new ADDynamicGameDescription<Descriptor>(static_cast<const Descriptor *>(*descriptor));
623 }
624 return err;
625 }
626};
627
632public:
641 Common::Error createInstance(OSystem *syst, Engine **engine, const DetectedGame &gameDescriptor, const void *metaEngineDescriptor) override;
642
647 virtual Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const = 0;
648
656 const char *getName() const override = 0;
657
663 Common::String getGameId(const char *target) const;
664
665public:
670
684 virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra = nullptr) const {
685 return ADDetectedGame();
686 }
687
693 bool getFilePropertiesExtern(uint md5Bytes, const FileMap &allFiles, MD5Properties md5prop, const Common::Path &fname, FileProperties &fileProps) const;
694
695protected:
710 const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override final;
711
715 virtual const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const { return nullptr; }
716
722
723private:
724 void initSubSystems(const ADGameDescription *gameDesc) const;
725};
726
727template<class Descriptor>
729protected:
730 virtual Common::Error createInstance(OSystem *syst, Engine **engine, const Descriptor *desc) const = 0;
731 Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const override final {
732 return createInstance(syst, engine, static_cast<const Descriptor *>(desc));
733 }
734
735 void deleteInstance(Engine *engine, const DetectedGame &gameDescriptor, const void *meDescriptor) override {
736 delete engine;
737 delete static_cast<ADDynamicGameDescription<Descriptor> *>(
738 const_cast<void *>(meDescriptor));
739 }
740
741private:
742 // Silence overloaded-virtual warning from clang
744};
745
749class AdvancedDetectorCacheManager : public Common::Singleton<AdvancedDetectorCacheManager> {
750public:
751 void setMD5(const Common::String &fname, const Common::String &md5) {
752 md5HashMap.setVal(fname, md5);
753 }
754
755 const Common::String &getMD5(const Common::String &fname) const {
756 return md5HashMap.getVal(fname);
757 }
758
759 void setSize(const Common::String &fname, int64 size) {
760 sizeHashMap.setVal(fname, size);
761 }
762
763 int64 getSize(const Common::String &fname) const {
764 return sizeHashMap.getVal(fname);
765 }
766
767 bool containsMD5(const Common::String &fname) const {
768 return (md5HashMap.contains(fname) && sizeHashMap.contains(fname));
769 }
770
771 void addArchive(const Common::FSNode &node, Common::Archive *archivePtr) {
772 if (!archivePtr)
773 return;
774
775 Common::Path filename = node.getPath();
776
777 if (archiveHashMap.contains(filename)) {
778 delete archiveHashMap[filename];
779 }
780
781 archiveHashMap.setVal(filename, archivePtr);
782 }
783
784 Common::Archive *getArchive(const Common::FSNode &node) const {
785 return archiveHashMap.getValOrDefault(node.getPath(), nullptr);
786 }
787
789 clear();
790 }
791
792 void clearArchives() {
793 for (auto &entry : archiveHashMap) {
794 delete entry._value;
795 }
796 archiveHashMap.clear(true);
797 }
798
799 void clear() {
800 md5HashMap.clear(true);
801 sizeHashMap.clear(true);
802 clearArchives();
803 }
804
805private:
807
811 FileHashMap md5HashMap;
812 SizeHashMap sizeHashMap;
813 ArchiveHashMap archiveHashMap;
814};
815
817#define ADCacheMan AdvancedDetectorCacheManager::instance()
819#endif
Definition: advancedDetector.h:271
Definition: advancedDetector.h:749
Definition: advancedDetector.h:631
virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra=nullptr) const
Definition: advancedDetector.h:684
bool getFilePropertiesExtern(uint md5Bytes, const FileMap &allFiles, MD5Properties md5prop, const Common::Path &fname, FileProperties &fileProps) const
virtual const ADExtraGuiOptionsMap * getAdvancedExtraGuiOptions() const
Definition: advancedDetector.h:715
const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override final
Common::HashMap< Common::Path, Common::FSNode, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo > FileMap
Definition: advancedDetector.h:669
const char * getName() const override=0
Common::String getGameId(const char *target) const
bool checkExtendedSaves(MetaEngineFeature f) const
virtual Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const =0
Common::Error createInstance(OSystem *syst, Engine **engine, const DetectedGame &gameDescriptor, const void *metaEngineDescriptor) override
Definition: advancedDetector.h:410
ADDetectedGame detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const
const uint _descItemSize
Definition: advancedDetector.h:426
int getGameVariantCount() const override final
Definition: advancedDetector.h:520
uint32 _flags
Definition: advancedDetector.h:451
void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::Path &parentName=Common::Path()) const
const PlainGameDescriptor * _gameIds
Definition: advancedDetector.h:432
DetectedGames detectGames(const Common::FSList &fslist, uint32 skipADFlags, bool skipIncomplete) override
uint getMD5Bytes() const override final
Definition: advancedDetector.h:518
PlainGameList getSupportedGames() const override
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override
const byte * _gameDescriptors
Definition: advancedDetector.h:419
uint _md5Bytes
Definition: advancedDetector.h:443
bool cleanupPirated(ADDetectedGames &matched) const
AdvancedMetaEngineDetectionBase(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds)
void dumpDetectionEntries() const override
PlainGameDescriptor findGame(const char *gameId) const override
virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra=nullptr) const
Definition: advancedDetector.h:544
int _maxAutogenLength
Definition: advancedDetector.h:483
Common::String _guiOptions
Definition: advancedDetector.h:459
bool getFileProperties(const FileMap &allFiles, MD5Properties md5prop, const Common::Path &fname, FileProperties &fileProps) const
virtual ADDetectedGames detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra, uint32 skipADFlags=0, bool skipIncomplete=false)
uint32 _maxScanDepth
Definition: advancedDetector.h:466
const char *const * _directoryGlobs
Definition: advancedDetector.h:476
virtual DetectedGame toDetectedGame(const ADDetectedGame &adGame, ADDetectedGameExtraInfo *extraInfo=nullptr) const
int _fullPathGlobsDepth
Definition: advancedDetector.h:490
static Common::String sanitizeName(const char *name, int maxLen)
Common::HashMap< Common::Path, Common::FSNode, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo > FileMap
Definition: advancedDetector.h:538
Definition: advancedDetector.h:611
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override
Definition: advancedDetector.h:615
Definition: advancedDetector.h:728
Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const override final
Definition: advancedDetector.h:731
void deleteInstance(Engine *engine, const DetectedGame &gameDescriptor, const void *meDescriptor) override
Definition: advancedDetector.h:735
Definition: archive.h:141
Definition: array.h:52
Definition: error.h:81
ErrorCode getCode() const
Definition: error.h:112
Definition: fs.h:57
Definition: fs.h:69
Definition: path.h:52
Definition: singleton.h:42
Definition: str.h:59
Definition: engine.h:149
Definition: metaengine.h:126
Definition: metaengine.h:202
MetaEngineFeature
Definition: metaengine.h:419
Definition: system.h:166
Definition: game.h:64
@ kNoError
No error occurred.
Definition: error.h:48
bool contains(const Key &key) const
Definition: hashmap.h:598
Val & getVal(const Key &key)
Definition: hashmap.h:637
void clear(bool shrinkArray=0)
Definition: hashmap.h:431
Language
Definition: language.h:45
Platform
Definition: platform.h:93
#define ARRAYSIZE(x)
Definition: util.h:114
ADGameFlags
Definition: advancedDetector.h:138
Common::Array< ADDetectedGame > ADDetectedGames
Definition: advancedDetector.h:322
ADFlags
Definition: advancedDetector.h:346
@ ADGF_DEMO
Add "-demo" to gameid.
Definition: advancedDetector.h:157
@ ADGF_DVD
Add "-dvd" to gameid.
Definition: advancedDetector.h:156
@ ADGF_USEEXTRAASTITLE
Use ADGameDescription::extra as the main game title, not gameid.
Definition: advancedDetector.h:152
@ ADGF_ADDON
An add-on game, that cannot be run independently without its base game.
Definition: advancedDetector.h:140
@ ADGF_AUTOGENTARGET
Automatically generate gameid from ADGameDescription::extra.
Definition: advancedDetector.h:142
@ ADGF_REMASTERED
Add "-remastered' to gameid.
Definition: advancedDetector.h:158
@ ADGF_NO_FLAGS
No flags.
Definition: advancedDetector.h:139
@ ADGF_DROPPLATFORM
Do not add platform to gameid.
Definition: advancedDetector.h:154
@ ADGF_UNSUPPORTED
Definition: advancedDetector.h:146
@ ADGF_CD
Add "-cd" to gameid.
Definition: advancedDetector.h:155
@ ADGF_DROPLANGUAGE
Do not add language to gameid.
Definition: advancedDetector.h:153
@ ADGF_TESTING
Flag to designate not yet officially supported games that are fit for public testing.
Definition: advancedDetector.h:144
@ ADGF_WARNING
Definition: advancedDetector.h:148
@ ADGF_TAILMD5
Calculate the MD5 for this entry from the end of the file.
Definition: advancedDetector.h:141
@ ADGF_MACRESFORK
Calculate the MD5 for this entry from the resource fork.
Definition: advancedDetector.h:151
@ ADGF_UNSTABLE
Flag to designate not yet officially supported games that are not fit for public testing.
Definition: advancedDetector.h:143
@ ADGF_ADDENGLISH
Always add English as a language option.
Definition: advancedDetector.h:150
@ ADGF_PIRATED
Flag to designate well-known pirated versions with cracks.
Definition: advancedDetector.h:145
@ kADFlagUseExtraAsHint
Definition: advancedDetector.h:357
@ kADFlagCanPlayUnknownVariants
Definition: advancedDetector.h:387
@ kADFlagCanTranscodeTraditionalChineseToSimplified
Definition: advancedDetector.h:392
@ kADFlagPreferFallbackDetection
Definition: advancedDetector.h:380
@ kADFlagMatchFullPaths
Definition: advancedDetector.h:370
MD5Properties
Definition: game.h:106
Definition: algorithm.h:29
Definition: advancedDetector.h:301
Common::String targetID
Definition: advancedDetector.h:303
Common::String gameName
Definition: advancedDetector.h:302
Definition: advancedDetector.h:309
ADDetectedGame(const ADGameDescription *d)
Definition: advancedDetector.h:318
const ADGameDescription * desc
Definition: advancedDetector.h:312
bool hasUnknownFiles
Definition: advancedDetector.h:310
FilePropertiesMap matchedFiles
Definition: advancedDetector.h:311
Definition: advancedDetector.h:400
ExtraGuiOption option
Definition: advancedDetector.h:402
const char * guioFlag
Definition: advancedDetector.h:401
Definition: advancedDetector.h:331
const ADGameDescription * desc
Definition: advancedDetector.h:336
const char * filenames[10]
Definition: advancedDetector.h:342
Definition: advancedDetector.h:164
const char * guiOptions
Definition: advancedDetector.h:216
uint32 sizeBuffer() const
Definition: advancedDetector.h:221
const char * extra
Definition: advancedDetector.h:181
uint32 flags
Definition: advancedDetector.h:207
Common::Platform platform
Definition: advancedDetector.h:199
const char * gameId
Definition: advancedDetector.h:170
ADGameFileDescription filesDescriptions[14]
Definition: advancedDetector.h:189
void * toBuffer(void *buffer)
Definition: advancedDetector.h:239
Common::Language language
Definition: advancedDetector.h:194
Definition: advancedDetector.h:78
uint16 fileType
Optional. Not used during detection, only by engines.
Definition: advancedDetector.h:80
const char * md5
MD5 of (the beginning of) the described file. Optional. Set to NULL to ignore.
Definition: advancedDetector.h:81
const char * fileName
Name of the described file.
Definition: advancedDetector.h:79
uint32 fileSize
Size of the described file. Set to AD_NO_SIZE to ignore.
Definition: advancedDetector.h:82
Definition: game.h:146
Definition: metaengine.h:70
Definition: game.h:121
Definition: game.h:49