ScummVM API documentation
resource.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 SCI_RESOURCE_RESOURCE_H
23 #define SCI_RESOURCE_RESOURCE_H
24 
25 #include "common/str.h"
26 #include "common/list.h"
27 #include "common/hashmap.h"
28 
29 #include "sci/graphics/helpers.h" // for ViewType
30 #include "sci/resource/decompressor.h"
31 #include "sci/sci.h"
32 #include "sci/util.h"
33 #include "sci/version.h"
34 
35 namespace Common {
36 class File;
37 class FSList;
38 class FSNode;
39 class WriteStream;
40 class SeekableReadStream;
41 }
42 
43 namespace Sci {
44 
45 enum {
46 #ifdef ENABLE_SCI32
47  // Hack to treat RESMAP.PAT/RESSCI.PAT as the highest volume
48  kResPatVolumeNumber = 100,
49 #endif
50 
52 
55 };
56 
59  kResStatusNoMalloc = 0,
60  kResStatusAllocated,
63 };
64 
67  SCI_ERROR_NONE = 0,
68  SCI_ERROR_IO_ERROR = 1,
69  SCI_ERROR_EMPTY_RESOURCE = 2,
71  SCI_ERROR_RESMAP_NOT_FOUND = 4,
73  SCI_ERROR_UNKNOWN_COMPRESSION = 6,
76 };
77 
78 enum {
80 };
81 
82 enum ResourceType {
83  kResourceTypeView = 0,
84  kResourceTypePic,
85  kResourceTypeScript,
86  kResourceTypeText,
87  kResourceTypeSound,
88  kResourceTypeMemory,
89  kResourceTypeVocab,
90  kResourceTypeFont,
91  kResourceTypeCursor,
92  kResourceTypePatch,
93  kResourceTypeBitmap,
94  kResourceTypePalette,
95  kResourceTypeCdAudio = 12,
96 #ifdef ENABLE_SCI32
97  kResourceTypeWave = 12,
98 #endif
99  kResourceTypeAudio,
100  kResourceTypeSync,
101  kResourceTypeMessage,
102  kResourceTypeMap,
103  kResourceTypeHeap,
104  kResourceTypeAudio36,
105  kResourceTypeSync36,
106  kResourceTypeTranslation, // Currently unsupported
107 
108  // SCI2.1+ Resources
109  kResourceTypeRobot,
110  kResourceTypeVMD,
111  kResourceTypeChunk,
112  kResourceTypeAnimation,
113 
114  // SCI3 Resources
115  kResourceTypeEtc,
116  kResourceTypeDuck,
117  kResourceTypeClut,
118  kResourceTypeTGA,
119  kResourceTypeZZZ,
120 
121  // Mac-only resources
122  kResourceTypeMacIconBarPictN, // IBIN resources (icon bar, not selected)
123  kResourceTypeMacIconBarPictS, // IBIS resources (icon bar, selected)
124  kResourceTypeMacPict, // PICT resources (inventory)
125 
126  kResourceTypeRave, // KQ6 hires RAVE (special sync) resources
127 
128  kResourceTypeInvalid
129 };
130 
131 const char *getResourceTypeName(ResourceType restype);
132 const char *getResourceTypeExtension(ResourceType restype);
133 
134 enum ResVersion {
135  kResVersionUnknown,
136  kResVersionSci0Sci1Early,
137  kResVersionSci1Middle,
138  kResVersionKQ5FMT,
139  kResVersionSci1Late,
140  kResVersionSci11,
141  kResVersionSci11Mac,
142  kResVersionSci2,
143  kResVersionSci3
144 };
145 
151 
155 const char *getSciVersionDesc(SciVersion version);
156 
157 class ResourceManager;
158 class ResourceSource;
159 class ResourcePatcher;
160 
161 class ResourceId {
162  static inline ResourceType fixupType(ResourceType type) {
163  if (type >= kResourceTypeInvalid)
164  return kResourceTypeInvalid;
165  return type;
166  }
167 
168  ResourceType _type;
169  uint16 _number;
170  uint32 _tuple; // Only used for audio36 and sync36
171 
172  static Common::String intToBase36(uint32 number, int minChar) {
173  // Convert from an integer to a base36 string
174  Common::String string;
175 
176  while (minChar--) {
177  int character = number % 36;
178  string = ((character < 10) ? (character + '0') : (character + 'A' - 10)) + string;
179  number /= 36;
180  }
181 
182  return string;
183  }
184 
185  friend void syncWithSerializer(Common::Serializer &s, ResourceId &obj);
186 
187 public:
188  ResourceId() : _type(kResourceTypeInvalid), _number(0), _tuple(0) { }
189 
190  ResourceId(ResourceType type_, uint16 number_, uint32 tuple_ = 0)
191  : _type(fixupType(type_)), _number(number_), _tuple(tuple_) {
192  }
193 
194  ResourceId(ResourceType type_, uint16 number_, byte noun, byte verb, byte cond, byte seq)
195  : _type(fixupType(type_)), _number(number_) {
196  _tuple = (noun << 24) | (verb << 16) | (cond << 8) | seq;
197  }
198 
199  Common::String toString() const {
200  Common::String retStr = Common::String::format("%s.%d", getResourceTypeName(_type), _number);
201 
202  if (_tuple != 0) {
203  retStr += Common::String::format("(%d, %d, %d, %d)", _tuple >> 24, (_tuple >> 16) & 0xff, (_tuple >> 8) & 0xff, _tuple & 0xff);
204  }
205 
206  return retStr;
207  }
208 
209  // Convert from a resource ID to a base36 patch name
210  Common::String toPatchNameBase36() const {
211  Common::String output;
212 
213  if (getSciVersion() >= SCI_VERSION_2) {
214  output += (getType() == kResourceTypeAudio36) ? 'A' : 'S'; // Identifier
215  } else {
216  output += (getType() == kResourceTypeAudio36) ? '@' : '#'; // Identifier
217  }
218  output += intToBase36(getNumber(), 3); // Map
219  output += intToBase36(getTuple() >> 24, 2); // Noun
220  output += intToBase36((getTuple() >> 16) & 0xff, 2); // Verb
221  output += '.'; // Separator
222  output += intToBase36((getTuple() >> 8) & 0xff, 2); // Cond
223  output += intToBase36(getTuple() & 0xff, 1); // Seq
224 
225  assert(output.size() == 12); // We should always get 12 characters in the end
226  return output;
227  }
228 
229  inline ResourceType getType() const { return _type; }
230  inline uint16 getNumber() const { return _number; }
231  inline uint32 getTuple() const { return _tuple; }
232 
233  inline uint hash() const {
234  return ((uint)((_type << 16) | _number)) ^ _tuple;
235  }
236 
237  bool operator==(const ResourceId &other) const {
238  return (_type == other._type) && (_number == other._number) && (_tuple == other._tuple);
239  }
240 
241  bool operator!=(const ResourceId &other) const {
242  return !operator==(other);
243  }
244 
245  bool operator<(const ResourceId &other) const {
246  return (_type < other._type) || ((_type == other._type) && (_number < other._number))
247  || ((_type == other._type) && (_number == other._number) && (_tuple < other._tuple));
248  }
249 };
250 
251 struct ResourceIdHash : public Common::UnaryFunction<ResourceId, uint> {
252  uint operator()(ResourceId val) const { return val.hash(); }
253 };
254 
256 class Resource : public SciSpan<const byte> {
257  friend class ResourceManager;
258  friend class ResourcePatcher;
259 
260  // FIXME: These 'friend' declarations are meant to be a temporary hack to
261  // ease transition to the ResourceSource class system.
262  friend class ResourceSource;
263  friend class PatchResourceSource;
264  friend class WaveResourceSource;
265  friend class AudioVolumeResourceSource;
266  friend class MacResourceForkResourceSource;
267 #ifdef ENABLE_SCI32
268  friend class ChunkResourceSource;
269 #endif
270 
271 protected:
277  byte *_header;
278  uint32 _headerSize;
279 
280 public:
281  Resource(ResourceManager *resMan, ResourceId id);
282  ~Resource();
283  void unalloc();
284 
285  inline ResourceType getType() const { return _id.getType(); }
286  inline uint16 getNumber() const { return _id.getNumber(); }
287  bool isLocked() const { return _status == kResStatusLocked; }
292  void writeToStream(Common::WriteStream *stream) const;
293 
294 #ifdef ENABLE_SCI32
295  Common::SeekableReadStream *makeStream() const;
296 #endif
297 
298  const Common::Path &getResourceLocation() const;
299 
300  // FIXME: This audio specific method is a hack. After all, why should a
301  // Resource have audio specific methods? But for now we keep this, as it
302  // eases transition.
303  uint32 getAudioCompressionType() const;
304 
305  uint16 getNumLockers() const { return _lockers; }
306 
307 protected:
308  ResourceId _id; // TODO: _id could almost be made const, only readResourceInfo() modifies it...
309  int32 _fileOffset;
310  ResourceStatus _status;
311  uint16 _lockers;
312  ResourceSource *_source;
313  ResourceManager *_resMan;
314 
315  bool loadPatch(Common::SeekableReadStream *file);
316  bool loadFromPatchFile();
317  bool loadFromWaveFile(Common::SeekableReadStream *file);
318  bool loadFromAudioVolumeSCI1(Common::SeekableReadStream *file);
319  bool loadFromAudioVolumeSCI11(Common::SeekableReadStream *file);
320  int decompress(ResVersion volVersion, Common::SeekableReadStream *file);
321  int readResourceInfo(ResVersion volVersion, Common::SeekableReadStream *file, uint32 &szPacked, ResourceCompression &compression);
322 };
323 
325 
328  // FIXME: These 'friend' declarations are meant to be a temporary hack to
329  // ease transition to the ResourceSource class system.
330  friend class ResourceSource;
331  friend class DirectoryResourceSource;
332  friend class PatchResourceSource;
333  friend class ExtMapResourceSource;
334  friend class IntMapResourceSource;
335  friend class AudioVolumeResourceSource;
336  friend class ExtAudioMapResourceSource;
337  friend class WaveResourceSource;
338  friend class MacResourceForkResourceSource;
339  friend class ResourcePatcher;
340 #ifdef ENABLE_SCI32
341  friend class ChunkResourceSource;
342 #endif
343 
344 public:
348  ResourceManager(const bool detectionMode = false);
349  ~ResourceManager();
350 
351 
355  void init();
356 
360  void addAppropriateSources();
361 
365  void addAppropriateSourcesForDetection(const Common::FSList &fslist); // TODO: Switch from FSList to Common::Archive?
366 
375  Resource *findResource(ResourceId id, bool lock);
376 
381  void unlockResource(Resource *res);
382 
395  Resource *testResource(const ResourceId &id) const;
396 
403  Common::List<ResourceId> listResources(ResourceType type, int mapNumber = -1);
404 
408  bool hasResourceType(ResourceType type);
409 
410  bool setAudioLanguage(int language);
411  void unloadAudioLanguage();
412  int getAudioLanguage() const;
413  void changeAudioDirectory(const Common::Path &path);
414  void changeMacAudioDirectory(const Common::Path &path);
415  bool isGMTrackIncluded();
416  bool isSci11Mac() const { return _volVersion == kResVersionSci11Mac; }
417  ViewType getViewType() const { return _viewType; }
418  const char *getMapVersionDesc() const { return versionDescription(_mapVersion); }
419  const char *getVolVersionDesc() const { return versionDescription(_volVersion); }
420  ResVersion getVolVersion() const { return _volVersion; }
421 
428  void addNewGMPatch(SciGameId gameId);
429  void addNewD110Patch(SciGameId gameId);
430 
431 #ifdef ENABLE_SCI32
432 
436  void addResourcesFromChunk(uint16 id);
437 
441  void findDisc(const int16 discNo);
442 
446  int16 getCurrentDiscNo() const { return _currentDiscNo; }
447 
448 private:
452  int16 _currentDiscNo;
453 
458  bool _multiDiscAudio;
459 
460 public:
461 #endif
462 
463  // Detects, if standard font of current game includes extended characters (>0x80)
464  bool detectFontExtended();
465  // Detects, if SCI1.1 game uses palette merging
466  bool detectPaletteMergingSci11();
467  // Detects, if SCI0EARLY game also has SCI0EARLY sound resources
468  bool detectEarlySound();
469 
473  Common::String findSierraGameId();
474 
481  reg_t findGameObject(const bool addSci11ScriptOffset);
482 
488  ResourceType convertResType(byte type);
489 
490 protected:
491  bool _detectionMode;
492 
493  // Maximum number of bytes to allow being allocated for resources
494  // Note: maxMemory will not be interpreted as a hard limit, only as a restriction
495  // for resources which are not explicitly locked. However, a warning will be
496  // issued whenever this limit is exceeded.
497  int _maxMemoryLRU;
498 
499  ViewType _viewType; // Used to determine if the game has EGA or VGA graphics
501  SourcesList _sources;
505  ResourceMap _resMap;
508  ResVersion _volVersion;
509  ResVersion _mapVersion;
510  bool _isSci2Mac;
511 
516  ResourceSource *addPatchDir(const Common::Path &path);
517 
518  ResourceSource *findVolume(ResourceSource *map, int volume_nr);
519 
525  ResourceSource *addSource(ResourceSource *source);
526 
534  ResourceSource *addExternalMap(const Common::Path &filename, int volume_nr = 0);
535 
536  ResourceSource *addExternalMap(const Common::FSNode *mapFile, int volume_nr = 0);
537 
544  void scanNewSources();
545 
546  bool addAudioSources();
547  void addScriptChunkSources();
548  void freeResourceSources();
549 
555  const char *versionDescription(ResVersion version) const;
556 
562  Common::SeekableReadStream *getVolumeFile(ResourceSource *source);
563  void disposeVolumeFileStream(Common::SeekableReadStream *fileStream, ResourceSource *source);
564  void loadResource(Resource *res);
565  void freeOldResources();
566  bool validateResource(const ResourceId &resourceId, const Common::Path &sourceMapLocation, const Common::Path &sourceName, const uint32 offset, const uint32 size, const uint32 sourceSize) const;
567  Resource *addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size = 0, const Common::Path &sourceMapLocation = Common::Path("(no map location)"));
568  Resource *updateResource(ResourceId resId, ResourceSource *src, uint32 size, const Common::Path &sourceMapLocation = Common::Path("(no map location)"));
569  Resource *updateResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size, const Common::Path &sourceMapLocation = Common::Path("(no map location)"));
570  void removeAudioResource(ResourceId resId);
571 
573  ResVersion detectMapVersion();
574  ResVersion detectVolVersion();
575 #ifdef ENABLE_SCI32
576  bool detectSci2Mac();
577 #endif
578 
584  int readResourceMapSCI0(ResourceSource *map);
585 
591  int readResourceMapSCI1(ResourceSource *map);
592 
598  int readAudioMapSCI11(IntMapResourceSource *map);
599 
606  int readAudioMapSCI1(ResourceSource *map, bool unload = false);
607 
613  void readResourcePatches();
614  void readResourcePatchesBase36();
615 
620  bool isBlacklistedPatch(const ResourceId &resId) const;
621 
622  void processPatch(ResourceSource *source, ResourceType resourceType, uint16 resourceNr, uint32 tuple = 0);
623 
627  void readWaveAudioPatches();
628  void processWavePatch(ResourceId resourceId, const Common::Path &name);
629 
633 #ifdef ENABLE_SCI32
634  void readAIFFAudioPatches();
635 #endif
636 
645  bool hasOldScriptHeader();
646 
647  void addToLRU(Resource *res);
648  void removeFromLRU(Resource *res);
649 
650  ResourceCompression getViewCompression();
651  ViewType detectViewType();
652  bool hasSci0Voc999();
653  bool hasSci1Voc900();
654  bool checkResourceDataForSignature(Resource *resource, const byte *signature);
655  bool checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2);
656  void detectSciVersion();
657 
658 public:
660  Common::Path getMacExecutableName() const;
661  bool isKoreanMessageMap(ResourceSource *source);
662 
663 private:
664  // For better or worse, because the patcher is added as a ResourceSource,
665  // its destruction is managed by freeResourceSources.
666  ResourcePatcher *_patcher;
667  bool _hasBadResources;
668 };
669 
671 public:
672  struct Channel {
673  byte number;
674  byte flags;
675  byte poly;
676  uint16 prio;
677  SciSpan<const byte> data;
678  uint16 curPos;
679  long time;
680  byte prev;
681 
682  Channel() :
683  number(0),
684  flags(0),
685  poly(0),
686  prio(0),
687  data(),
688  curPos(0) {
689  time = 0;
690  prev = 0;
691  }
692  };
693 
694  struct Track {
695  byte type;
696  byte channelCount;
697  SciSpan<const byte> header;
698  Channel *channels;
699  int16 digitalChannelNr;
700  uint16 digitalSampleRate;
701  uint16 digitalSampleSize;
702  uint16 digitalSampleStart;
703  uint16 digitalSampleEnd;
704  };
705 public:
706  SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion);
707  ~SoundResource();
708 #if 0
709  Track *getTrackByNumber(uint16 number);
710 #endif
711  Track *getTrackByType(byte type);
712  Track *getDigitalTrack();
713  int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
714 #if 0
715  byte getInitialVoiceCount(byte channel);
716 #endif
717  byte getSoundPriority() const { return _soundPriority; }
718  bool exists() const { return _resource != nullptr; }
719 
720 private:
721  SciVersion _soundVersion;
722  int _trackCount;
723  Track *_tracks;
724  Resource *_resource;
725  ResourceManager *_resMan;
726  byte _soundPriority;
727 };
728 
729 ResourceId convertPatchNameBase36(ResourceType type, const Common::String &filename);
730 
731 } // End of namespace Sci
732 
733 #endif // SCI_RESOURCE_RESOURCE_H
ResVersion _mapVersion
resource.map version
Definition: resource.h:509
uint16 _lockers
Definition: resource.h:311
Definition: str.h:59
Definition: resource.h:670
byte * _header
Definition: resource.h:277
Definition: resource.h:70
static String format(MSVC_PRINTF const char *fmt,...) GCC_PRINTF(1
ResourceSource * _audioMapSCI1
Currently loaded audio map for SCI1.
Definition: resource.h:507
Definition: stream.h:77
patch type + header size
Definition: resource.h:51
int _memoryLocked
Amount of resource bytes in locked memory.
Definition: resource.h:502
SciVersion
Definition: detection.h:135
SciVersion getSciVersionForDetection()
Definition: resource.h:694
int32 _fileOffset
Definition: resource.h:309
Definition: list.h:44
Definition: path.h:52
Definition: resource_intern.h:92
Definition: stream.h:745
Definition: serializer.h:79
Definition: resource.h:327
Definition: resource_intern.h:178
Definition: resource.h:672
Max number of simultaneously opened volumes.
Definition: resource.h:79
Definition: resource_intern.h:99
Definition: resource.h:61
Definition: resource_intern.h:197
Definition: resource_intern.h:135
Common::List< Common::File * > _volumeFiles
list of opened volume files
Definition: resource.h:506
Definition: resource.h:75
Definition: resource.h:62
Definition: resource.h:54
Definition: resource_intern.h:126
Definition: algorithm.h:29
Definition: fs.h:69
const char * getSciVersionDesc(SciVersion version)
Definition: resource.h:256
Definition: console.h:28
Definition: fs.h:57
Definition: resource_patcher.h:90
Definition: resource_intern.h:145
Definition: resource.h:161
Definition: resource_intern.h:187
ResourceErrorCodes
Definition: resource.h:66
ResVersion _volVersion
resource.0xx version
Definition: resource.h:508
Definition: util.h:251
int _memoryLRU
Amount of resource bytes under LRU control.
Definition: resource.h:503
Definition: resource_intern.h:48
Definition: vm_types.h:39
Definition: resource.h:74
Definition: func.h:43
Definition: resource.h:251
Common::List< Resource * > _LRU
Last Resource Used list.
Definition: resource.h:504
ResourceStatus
Definition: resource.h:58