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 ? (uint32)strlen(field) + 1 : 0;
50 }
51 static 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 
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_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)
159 };
160 
170  const char *gameId;
171 
181  const char *extra;
182 
189  ADGameFileDescription filesDescriptions[14];
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 
270 template<class T>
271 class ADDynamicGameDescription : public T {
272 public:
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 
294 private:
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 
346 enum ADFlags {
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 
411 protected:
419  const byte *_gameDescriptors;
420 
426  const uint _descItemSize;
427 
433 
443  uint _md5Bytes;
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 
497 public:
503  PlainGameList getSupportedGames() const override;
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 
534 protected:
539 
544  virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra = nullptr) const {
545  return ADDetectedGame();
546  }
547 
548 private:
549  void preprocessDescriptions();
550  static Common::StringArray getPathsFromEntry(const ADGameDescription *g);
551  bool isEntryGrayListed(const ADGameDescription *g) const;
552  void detectClashes() const;
553 
554 private:
557  bool _hashMapsInited;
558 
559 protected:
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 
610 template<class Descriptor>
612 protected:
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 
632 public:
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 
658 public:
663 
677  virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra = nullptr) const {
678  return ADDetectedGame();
679  }
680 
686  bool getFilePropertiesExtern(uint md5Bytes, const FileMap &allFiles, MD5Properties md5prop, const Common::Path &fname, FileProperties &fileProps) const;
687 
688 protected:
703  const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override final;
704 
708  virtual const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const { return nullptr; }
709 
714  bool checkExtendedSaves(MetaEngineFeature f) const;
715 
716 private:
717  void initSubSystems(const ADGameDescription *gameDesc) const;
718 };
719 
720 template<class Descriptor>
722 protected:
723  virtual Common::Error createInstance(OSystem *syst, Engine **engine, const Descriptor *desc) const = 0;
724  Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const override final {
725  return createInstance(syst, engine, static_cast<const Descriptor *>(desc));
726  }
727 
728  void deleteInstance(Engine *engine, const DetectedGame &gameDescriptor, const void *meDescriptor) override {
729  delete engine;
730  delete static_cast<ADDynamicGameDescription<Descriptor> *>(
731  const_cast<void *>(meDescriptor));
732  }
733 
734 private:
735  // Silence overloaded-virtual warning from clang
737 };
738 
742 class AdvancedDetectorCacheManager : public Common::Singleton<AdvancedDetectorCacheManager> {
743 public:
744  void setMD5(const Common::String &fname, const Common::String &md5) {
745  md5HashMap.setVal(fname, md5);
746  }
747 
748  const Common::String &getMD5(const Common::String &fname) const {
749  return md5HashMap.getVal(fname);
750  }
751 
752  void setSize(const Common::String &fname, int64 size) {
753  sizeHashMap.setVal(fname, size);
754  }
755 
756  int64 getSize(const Common::String &fname) const {
757  return sizeHashMap.getVal(fname);
758  }
759 
760  bool containsMD5(const Common::String &fname) const {
761  return (md5HashMap.contains(fname) && sizeHashMap.contains(fname));
762  }
763 
764  void addArchive(const Common::FSNode &node, Common::Archive *archivePtr) {
765  if (!archivePtr)
766  return;
767 
768  Common::Path filename = node.getPath();
769 
770  if (archiveHashMap.contains(filename)) {
771  delete archiveHashMap[filename];
772  }
773 
774  archiveHashMap.setVal(filename, archivePtr);
775  }
776 
777  Common::Archive *getArchive(const Common::FSNode &node) const {
778  return archiveHashMap.getValOrDefault(node.getPath(), nullptr);
779  }
780 
782  clear();
783  }
784 
785  void clearArchives() {
786  for (auto &entry : archiveHashMap) {
787  delete entry._value;
788  }
789  archiveHashMap.clear(true);
790  }
791 
792  void clear() {
793  md5HashMap.clear(true);
794  sizeHashMap.clear(true);
795  clearArchives();
796  }
797 
798 private:
799  friend class Common::Singleton<AdvancedDetectorCacheManager>;
800 
804  FileHashMap md5HashMap;
805  SizeHashMap sizeHashMap;
806  ArchiveHashMap archiveHashMap;
807 };
808 
810 #define ADCacheMan AdvancedDetectorCacheManager::instance()
811 
812 #endif
#define ARRAYSIZE(x)
Definition: util.h:103
Definition: advancedDetector.h:301
Definition: metaengine.h:202
Always add English as a language option.
Definition: advancedDetector.h:150
Definition: str.h:59
uint32 sizeBuffer() const
Definition: advancedDetector.h:221
virtual const ADExtraGuiOptionsMap * getAdvancedExtraGuiOptions() const
Definition: advancedDetector.h:708
Flag to designate not yet officially supported games that are not fit for public testing.
Definition: advancedDetector.h:143
Definition: advancedDetector.h:380
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:419
const char *const * _directoryGlobs
Definition: advancedDetector.h:476
Definition: error.h:81
Definition: game.h:146
Definition: advancedDetector.h:611
ErrorCode getCode() const
Definition: error.h:112
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:322
Definition: array.h:52
uint32 _maxScanDepth
Definition: advancedDetector.h:466
const char * extra
Definition: advancedDetector.h:181
Definition: advancedDetector.h:164
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override
const ADGameDescription * desc
Definition: advancedDetector.h:312
Definition: game.h:121
Common::String _guiOptions
Definition: advancedDetector.h:459
const char * fileName
Name of the described file.
Definition: advancedDetector.h:79
const ADGameDescription * desc
Definition: advancedDetector.h:336
uint32 _flags
Definition: advancedDetector.h:451
uint _md5Bytes
Definition: advancedDetector.h:443
const char * gameId
Definition: advancedDetector.h:170
Do not add platform to gameid.
Definition: advancedDetector.h:154
No error occurred.
Definition: error.h:48
ADDetectedGame(const ADGameDescription *d)
Definition: advancedDetector.h:318
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:544
Definition: path.h:52
Definition: advancedDetector.h:631
No flags.
Definition: advancedDetector.h:139
uint16 fileType
Optional. Not used during detection, only by engines.
Definition: advancedDetector.h:80
Definition: advancedDetector.h:271
Definition: advancedDetector.h:370
Definition: advancedDetector.h:400
Definition: game.h:49
bool hasUnknownFiles
Definition: advancedDetector.h:310
uint32 flags
Definition: advancedDetector.h:207
Add "-dvd" to gameid.
Definition: advancedDetector.h:156
Calculate the MD5 for this entry from the resource fork.
Definition: advancedDetector.h:151
ADGameFlags
Definition: advancedDetector.h:138
ADFlags
Definition: advancedDetector.h:346
Definition: archive.h:141
Definition: advancedDetector.h:721
int _maxAutogenLength
Definition: advancedDetector.h:483
Flag to designate not yet officially supported games that are fit for public testing.
Definition: advancedDetector.h:144
void * toBuffer(void *buffer)
Definition: advancedDetector.h:239
Common::Language language
Definition: advancedDetector.h:194
Do not add language to gameid.
Definition: advancedDetector.h:153
Definition: metaengine.h:70
Add "-cd" to gameid.
Definition: advancedDetector.h:155
Automatically generate gameid from ADGameDescription::extra.
Definition: advancedDetector.h:142
const byte * _gameDescriptors
Definition: advancedDetector.h:419
Use ADGameDescription::extra as the main game title, not gameid.
Definition: advancedDetector.h:152
Path getPath() const
ExtraGuiOption option
Definition: advancedDetector.h:402
Definition: advancedDetector.h:387
An add-on game, that cannot be run independently without its base game.
Definition: advancedDetector.h:140
int getGameVariantCount() const override final
Definition: advancedDetector.h:520
Definition: algorithm.h:29
Definition: fs.h:69
Definition: advancedDetector.h:146
void deleteInstance(Engine *engine, const DetectedGame &gameDescriptor, const void *meDescriptor) override
Definition: advancedDetector.h:728
Definition: advancedDetector.h:742
Common::HashMap< Common::Path, Common::FSNode, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo > FileMap
Definition: advancedDetector.h:662
const char * guiOptions
Definition: advancedDetector.h:216
Definition: metaengine.h:126
const uint _descItemSize
Definition: advancedDetector.h:426
Definition: fs.h:57
Flag to designate well-known pirated versions with cracks.
Definition: advancedDetector.h:145
Definition: advancedDetector.h:309
uint getMD5Bytes() const override final
Definition: advancedDetector.h:518
Calculate the MD5 for this entry from the end of the file.
Definition: advancedDetector.h:141
virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra=nullptr) const
Definition: advancedDetector.h:677
Definition: advancedDetector.h:331
Definition: advancedDetector.h:148
Common::Error createInstance(OSystem *syst, Engine **engine, const DetectedGame &gameDescriptor, const void *metaEngineDescriptor) override
Common::String targetID
Definition: advancedDetector.h:303
Definition: advancedDetector.h:410
Definition: system.h:163
const PlainGameDescriptor * _gameIds
Definition: advancedDetector.h:432
FilePropertiesMap matchedFiles
Definition: advancedDetector.h:311
Definition: advancedDetector.h:392
Add "-demo" to gameid.
Definition: advancedDetector.h:157
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override
Definition: advancedDetector.h:615
Common::Platform platform
Definition: advancedDetector.h:199
Common::Error createInstance(OSystem *syst, Engine **engine, const void *desc) const override final
Definition: advancedDetector.h:724
Definition: engine.h:146
Definition: advancedDetector.h:357
int _fullPathGlobsDepth
Definition: advancedDetector.h:490
Platform
Definition: platform.h:46
Add "-remastered&#39; to gameid.
Definition: advancedDetector.h:158
Definition: singleton.h:42
const char * guioFlag
Definition: advancedDetector.h:401
Common::HashMap< Common::Path, Common::FSNode, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo > FileMap
Definition: advancedDetector.h:538
Common::String gameName
Definition: advancedDetector.h:302
Language
Definition: language.h:45
Definition: advancedDetector.h:78