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 
32 namespace Common {
33 class Error;
34 class FSList;
35 }
45 /* Some helpers functions to avoid code duplication */
46 namespace ADDynamicDescription {
47 
48 static inline uint32 strSizeBuffer(const char * const &field) {
49  return field ? strlen(field) + 1 : 0;
50 }
51 static inline void *strToBuffer(void *buffer, const char *&field) {
52  if (field) {
53  int len = 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 
61 static inline uint32 alignSizeBuffer() {
62  // We consider alignments up to pointer size
63  return sizeof(void *) - 1;
64 }
65 static 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 
138 enum ADGameFlags : uint {
140  ADGF_TAILMD5 = (1u << 16),
141  ADGF_AUTOGENTARGET = (1u << 17),
142  ADGF_UNSTABLE = (1u << 18),
143  ADGF_TESTING = (1u << 19),
144  ADGF_PIRATED = (1u << 20),
145  ADGF_UNSUPPORTED = (1u << 21),
147  ADGF_WARNING = (1u << 22),
149  ADGF_ADDENGLISH = (1u << 23),
150  ADGF_MACRESFORK = (1u << 24),
151  ADGF_USEEXTRAASTITLE = (1u << 25),
152  ADGF_DROPLANGUAGE = (1u << 26),
153  ADGF_DROPPLATFORM = (1u << 27),
154  ADGF_CD = (1u << 28),
155  ADGF_DVD = (1u << 29),
156  ADGF_DEMO = (1u << 30),
157  ADGF_REMASTERED = (1u << 31)
158 };
159 
169  const char *gameId;
170 
180  const char *extra;
181 
188  ADGameFileDescription filesDescriptions[14];
189 
194 
199 
206  uint32 flags;
207 
215  const char *guiOptions;
216 
220  uint32 sizeBuffer() const {
221  uint32 ret = 0;
222  ret += ADDynamicDescription::strSizeBuffer(gameId);
223  ret += ADDynamicDescription::strSizeBuffer(extra);
224  for(int i = 0; i < ARRAYSIZE(filesDescriptions); i++) {
225  ret += filesDescriptions[i].sizeBuffer();
226  }
227  ret += ADDynamicDescription::strSizeBuffer(guiOptions);
228  return ret;
229  }
230 
238  void *toBuffer(void *buffer) {
239  buffer = ADDynamicDescription::strToBuffer(buffer, gameId);
240  buffer = ADDynamicDescription::strToBuffer(buffer, extra);
241  for(int i = 0; i < ARRAYSIZE(filesDescriptions); i++) {
242  buffer = filesDescriptions[i].toBuffer(buffer);
243  }
244  buffer = ADDynamicDescription::strToBuffer(buffer, guiOptions);
245  return buffer;
246  }
247 };
248 
255 #define AD_GAME_DESCRIPTION_HELPERS(field) \
256  uint32 sizeBuffer() const { \
257  return field.sizeBuffer(); \
258  } \
259  void *toBuffer(void *buffer) { \
260  return field.toBuffer(buffer); \
261  }
262 
269 template<class T>
270 class ADDynamicGameDescription : public T {
271 public:
272  ADDynamicGameDescription(const T *other) : _buffer(nullptr) {
273  // First copy all fields
274  memcpy(static_cast<T*>(this), other, sizeof(T));
275 
276  // Then calculate the size of the dynamic buffer
277  // we will need to store evrything pointed at by
278  // the structures
279  uint32 sz = other->sizeBuffer();
280  _buffer = new byte[sz];
281 
282  // Finally copy every pointer in the buffer
283  // and make the structure point into it
284  void *end = this->toBuffer(_buffer);
285  assert(end <= _buffer + sz);
286  }
287 
289  delete[] _buffer;
290  }
291 
292 private:
293  byte *_buffer;
294 };
295 
302 };
303 
312  ADDetectedGame() : desc(nullptr), hasUnknownFiles(false) {}
316  explicit ADDetectedGame(const ADGameDescription *d) : desc(d), hasUnknownFiles(false) {}
317 };
318 
321 
326 #define AD_TABLE_END_MARKER \
327  { NULL, NULL, { { NULL, 0, NULL, 0 } }, Common::UNK_LANG, Common::kPlatformUnknown, ADGF_NO_FLAGS, GUIO0() }
328 
335 
340  const char *filenames[10];
341 };
342 
343 
344 enum ADFlags {
356 
369 
379 
386 
391 };
392 
393 
399  const char *guioFlag;
401 };
402 
403 #define AD_EXTRA_GUI_OPTIONS_TERMINATOR { 0, { 0, 0, 0, 0, 0, 0 } }
404 
409 protected:
417  const byte *_gameDescriptors;
418 
424  const uint _descItemSize;
425 
431 
441  uint _md5Bytes;
442 
449  uint32 _flags;
450 
458 
465 
474  const char * const *_directoryGlobs;
475 
482 
489 
493  AdvancedMetaEngineDetectionBase(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds);
494 
495 public:
501  PlainGameList getSupportedGames() const override;
502 
504  PlainGameDescriptor findGame(const char *gameId) const override;
505 
507  Common::Error identifyGame(DetectedGame &game, const void **descriptor) override;
508 
514  DetectedGames detectGames(const Common::FSList &fslist, uint32 skipADFlags, bool skipIncomplete) override;
515 
516  uint getMD5Bytes() const override final { return _md5Bytes; }
517 
518  int getGameVariantCount() const override final {
519  uint count = 0;
520  for (const byte *descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != nullptr; descPtr += _descItemSize)
521  ++count;
522  return count;
523  }
524 
525  void dumpDetectionEntries() const override final;
526 
527 protected:
532 
537  virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra = nullptr) const {
538  return ADDetectedGame();
539  }
540 
541 private:
542  void preprocessDescriptions();
543  static Common::StringArray getPathsFromEntry(const ADGameDescription *g);
544  bool isEntryGrayListed(const ADGameDescription *g) const;
545  void detectClashes() const;
546 
547 private:
550  bool _hashMapsInited;
551 
552 protected:
569  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);
570 
582  ADDetectedGame detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const;
583 
589  void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::Path &parentName = Common::Path()) const;
590 
592  bool getFileProperties(const FileMap &allFiles, MD5Properties md5prop, const Common::Path &fname, FileProperties &fileProps) const;
593 
595  virtual DetectedGame toDetectedGame(const ADDetectedGame &adGame, ADDetectedGameExtraInfo *extraInfo = nullptr) const;
596 
598  bool cleanupPirated(ADDetectedGames &matched) const;
599 
600  friend class FileMapArchive;
601 };
602 
603 template<class Descriptor>
605 protected:
606  AdvancedMetaEngineDetection(const Descriptor *descs, const PlainGameDescriptor *gameIds) : AdvancedMetaEngineDetectionBase(descs, sizeof(Descriptor), gameIds) {}
607 
608  Common::Error identifyGame(DetectedGame &game, const void **descriptor) override {
609  assert(descriptor);
611  if (err.getCode() != Common::kNoError) {
612  return err;
613  }
614  if (*descriptor) {
615  *descriptor = new ADDynamicGameDescription<Descriptor>(static_cast<const Descriptor *>(*descriptor));
616  }
617  return err;
618  }
619 };
620 
625 public:
634  Common::Error createInstance(OSystem *syst, Engine **engine, const DetectedGame &gameDescriptor, const void *metaEngineDescriptor) override;
635 
640  virtual Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const = 0;
641 
649  const char *getName() const override = 0;
650 
651 public:
656 
670  virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra = nullptr) const {
671  return ADDetectedGame();
672  }
673 
679  bool getFilePropertiesExtern(uint md5Bytes, const FileMap &allFiles, MD5Properties md5prop, const Common::Path &fname, FileProperties &fileProps) const;
680 
681 protected:
696  const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override final;
697 
701  virtual const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const { return nullptr; }
702 
707  bool checkExtendedSaves(MetaEngineFeature f) const;
708 
709 private:
710  void initSubSystems(const ADGameDescription *gameDesc) const;
711 };
712 
713 template<class Descriptor>
715 protected:
716  virtual Common::Error createInstance(OSystem *syst, Engine **engine, const Descriptor *desc) const = 0;
717  Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const override final {
718  return createInstance(syst, engine, static_cast<const Descriptor *>(desc));
719  }
720 
721  void deleteInstance(Engine *engine, const DetectedGame &gameDescriptor, const void *meDescriptor) override {
722  delete engine;
723  delete static_cast<ADDynamicGameDescription<Descriptor> *>(
724  const_cast<void *>(meDescriptor));
725  }
726 
727 private:
728  // Silence overloaded-virtual warning from clang
730 };
731 
735 class AdvancedDetectorCacheManager : public Common::Singleton<AdvancedDetectorCacheManager> {
736 public:
737  void setMD5(const Common::String &fname, const Common::String &md5) {
738  md5HashMap.setVal(fname, md5);
739  }
740 
741  const Common::String &getMD5(const Common::String &fname) const {
742  return md5HashMap.getVal(fname);
743  }
744 
745  void setSize(const Common::String &fname, int64 size) {
746  sizeHashMap.setVal(fname, size);
747  }
748 
749  int64 getSize(const Common::String &fname) const {
750  return sizeHashMap.getVal(fname);
751  }
752 
753  bool containsMD5(const Common::String &fname) const {
754  return (md5HashMap.contains(fname) && sizeHashMap.contains(fname));
755  }
756 
757  void addArchive(const Common::FSNode &node, Common::Archive *archivePtr) {
758  if (!archivePtr)
759  return;
760 
761  Common::Path filename = node.getPath();
762 
763  if (archiveHashMap.contains(filename)) {
764  delete archiveHashMap[filename];
765  }
766 
767  archiveHashMap.setVal(filename, archivePtr);
768  }
769 
770  Common::Archive *getArchive(const Common::FSNode &node) const {
771  return archiveHashMap.getValOrDefault(node.getPath(), nullptr);
772  }
773 
775  clear();
776  }
777 
778  void clearArchives() {
779  for (auto &entry : archiveHashMap) {
780  delete entry._value;
781  }
782  archiveHashMap.clear(true);
783  }
784 
785  void clear() {
786  md5HashMap.clear(true);
787  sizeHashMap.clear(true);
788  clearArchives();
789  }
790 
791 private:
792  friend class Common::Singleton<AdvancedDetectorCacheManager>;
793 
797  FileHashMap md5HashMap;
798  SizeHashMap sizeHashMap;
799  ArchiveHashMap archiveHashMap;
800 };
801 
803 #define ADCacheMan AdvancedDetectorCacheManager::instance()
804 
805 #endif
#define ARRAYSIZE(x)
Definition: util.h:91
Definition: advancedDetector.h:299
Definition: metaengine.h:196
Always add English as a language option.
Definition: advancedDetector.h:149
Definition: str.h:59
uint32 sizeBuffer() const
Definition: advancedDetector.h:220
virtual const ADExtraGuiOptionsMap * getAdvancedExtraGuiOptions() const
Definition: advancedDetector.h:701
Flag to designate not yet officially supported games that are not fit for public testing.
Definition: advancedDetector.h:142
Definition: advancedDetector.h:378
Definition: advancedDetector.h:46
uint32 fileSize
Size of the described file. Set to AD_NO_SIZE to ignore.
Definition: advancedDetector.h:82
MetaEngineFeature
Definition: metaengine.h:413
const char *const * _directoryGlobs
Definition: advancedDetector.h:474
Definition: error.h:84
Definition: game.h:147
Definition: advancedDetector.h:604
ErrorCode getCode() const
Definition: error.h:115
const char * md5
MD5 of (the beginning of) the described file. Optional. Set to NULL to ignore.
Definition: advancedDetector.h:81
Common::Array< ADDetectedGame > ADDetectedGames
Definition: advancedDetector.h:320
Definition: array.h:52
uint32 _maxScanDepth
Definition: advancedDetector.h:464
const char * extra
Definition: advancedDetector.h:180
Definition: advancedDetector.h:163
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override
const ADGameDescription * desc
Definition: advancedDetector.h:310
Definition: game.h:122
Common::String _guiOptions
Definition: advancedDetector.h:457
const char * fileName
Name of the described file.
Definition: advancedDetector.h:79
const ADGameDescription * desc
Definition: advancedDetector.h:334
uint32 _flags
Definition: advancedDetector.h:449
uint _md5Bytes
Definition: advancedDetector.h:441
const char * gameId
Definition: advancedDetector.h:169
Do not add platform to gameid.
Definition: advancedDetector.h:153
No error occurred.
Definition: error.h:48
ADDetectedGame(const ADGameDescription *d)
Definition: advancedDetector.h:316
MD5Properties
Definition: game.h:106
Definition: game.h:64
virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra=nullptr) const
Definition: advancedDetector.h:537
Definition: path.h:52
Definition: advancedDetector.h:624
No flags.
Definition: advancedDetector.h:139
uint16 fileType
Optional. Not used during detection, only by engines.
Definition: advancedDetector.h:80
Definition: advancedDetector.h:270
Definition: advancedDetector.h:368
Definition: advancedDetector.h:398
Definition: game.h:49
bool hasUnknownFiles
Definition: advancedDetector.h:308
uint32 flags
Definition: advancedDetector.h:206
Add "-dvd" to gameid.
Definition: advancedDetector.h:155
Calculate the MD5 for this entry from the resource fork.
Definition: advancedDetector.h:150
ADGameFlags
Definition: advancedDetector.h:138
ADFlags
Definition: advancedDetector.h:344
Definition: archive.h:141
Definition: advancedDetector.h:714
int _maxAutogenLength
Definition: advancedDetector.h:481
Flag to designate not yet officially supported games that are fit for public testing.
Definition: advancedDetector.h:143
void * toBuffer(void *buffer)
Definition: advancedDetector.h:238
Common::Language language
Definition: advancedDetector.h:193
Do not add language to gameid.
Definition: advancedDetector.h:152
Definition: metaengine.h:70
Add "-cd" to gameid.
Definition: advancedDetector.h:154
Automatically generate gameid from ADGameDescription::extra.
Definition: advancedDetector.h:141
const byte * _gameDescriptors
Definition: advancedDetector.h:417
Use ADGameDescription::extra as the main game title, not gameid.
Definition: advancedDetector.h:151
Path getPath() const
ExtraGuiOption option
Definition: advancedDetector.h:400
Definition: advancedDetector.h:385
int getGameVariantCount() const override final
Definition: advancedDetector.h:518
Definition: algorithm.h:29
Definition: fs.h:69
Definition: advancedDetector.h:145
void deleteInstance(Engine *engine, const DetectedGame &gameDescriptor, const void *meDescriptor) override
Definition: advancedDetector.h:721
Definition: advancedDetector.h:735
Common::HashMap< Common::Path, Common::FSNode, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo > FileMap
Definition: advancedDetector.h:655
const char * guiOptions
Definition: advancedDetector.h:215
Definition: metaengine.h:126
const uint _descItemSize
Definition: advancedDetector.h:424
Definition: fs.h:57
Flag to designate well-known pirated versions with cracks.
Definition: advancedDetector.h:144
Definition: advancedDetector.h:307
uint getMD5Bytes() const override final
Definition: advancedDetector.h:516
Calculate the MD5 for this entry from the end of the file.
Definition: advancedDetector.h:140
virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra=nullptr) const
Definition: advancedDetector.h:670
Definition: advancedDetector.h:329
Definition: advancedDetector.h:147
Common::Error createInstance(OSystem *syst, Engine **engine, const DetectedGame &gameDescriptor, const void *metaEngineDescriptor) override
Common::String targetID
Definition: advancedDetector.h:301
Definition: advancedDetector.h:408
Definition: system.h:161
const PlainGameDescriptor * _gameIds
Definition: advancedDetector.h:430
FilePropertiesMap matchedFiles
Definition: advancedDetector.h:309
Definition: advancedDetector.h:390
Add "-demo" to gameid.
Definition: advancedDetector.h:156
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override
Definition: advancedDetector.h:608
Common::Platform platform
Definition: advancedDetector.h:198
Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const override final
Definition: advancedDetector.h:717
Definition: engine.h:144
Definition: advancedDetector.h:355
int _fullPathGlobsDepth
Definition: advancedDetector.h:488
Platform
Definition: platform.h:46
Add "-remastered&#39; to gameid.
Definition: advancedDetector.h:157
Definition: singleton.h:42
const char * guioFlag
Definition: advancedDetector.h:399
Common::HashMap< Common::Path, Common::FSNode, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo > FileMap
Definition: advancedDetector.h:531
Common::String gameName
Definition: advancedDetector.h:300
Language
Definition: language.h:45
Definition: advancedDetector.h:78