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  int addAppropriateSources();
361 
365  int 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  void setAudioLanguage(int language);
411  int getAudioLanguage() const;
412  void changeAudioDirectory(const Common::Path &path);
413  void changeMacAudioDirectory(const Common::Path &path);
414  bool isGMTrackIncluded();
415  bool isSci11Mac() const { return _volVersion == kResVersionSci11Mac; }
416  ViewType getViewType() const { return _viewType; }
417  const char *getMapVersionDesc() const { return versionDescription(_mapVersion); }
418  const char *getVolVersionDesc() const { return versionDescription(_volVersion); }
419  ResVersion getVolVersion() const { return _volVersion; }
420 
427  void addNewGMPatch(SciGameId gameId);
428  void addNewD110Patch(SciGameId gameId);
429 
430 #ifdef ENABLE_SCI32
431 
435  void addResourcesFromChunk(uint16 id);
436 
440  void findDisc(const int16 discNo);
441 
445  int16 getCurrentDiscNo() const { return _currentDiscNo; }
446 
447 private:
451  int16 _currentDiscNo;
452 
457  bool _multiDiscAudio;
458 
459 public:
460 #endif
461 
462  // Detects, if standard font of current game includes extended characters (>0x80)
463  bool detectFontExtended();
464  // Detects, if SCI1.1 game uses palette merging
465  bool detectPaletteMergingSci11();
466  // Detects, if SCI0EARLY game also has SCI0EARLY sound resources
467  bool detectEarlySound();
468 
472  Common::String findSierraGameId();
473 
480  reg_t findGameObject(const bool addSci11ScriptOffset);
481 
487  ResourceType convertResType(byte type);
488 
489 protected:
490  bool _detectionMode;
491 
492  // Maximum number of bytes to allow being allocated for resources
493  // Note: maxMemory will not be interpreted as a hard limit, only as a restriction
494  // for resources which are not explicitly locked. However, a warning will be
495  // issued whenever this limit is exceeded.
496  int _maxMemoryLRU;
497 
498  ViewType _viewType; // Used to determine if the game has EGA or VGA graphics
500  SourcesList _sources;
504  ResourceMap _resMap;
507  ResVersion _volVersion;
508  ResVersion _mapVersion;
509  bool _isSci2Mac;
510 
515  ResourceSource *addPatchDir(const Common::Path &path);
516 
517  ResourceSource *findVolume(ResourceSource *map, int volume_nr);
518 
524  ResourceSource *addSource(ResourceSource *source);
525 
533  ResourceSource *addExternalMap(const Common::Path &filename, int volume_nr = 0);
534 
535  ResourceSource *addExternalMap(const Common::FSNode *mapFile, int volume_nr = 0);
536 
543  void scanNewSources();
544 
545  bool addAudioSources();
546  void addScriptChunkSources();
547  void freeResourceSources();
548 
554  const char *versionDescription(ResVersion version) const;
555 
561  Common::SeekableReadStream *getVolumeFile(ResourceSource *source);
562  void disposeVolumeFileStream(Common::SeekableReadStream *fileStream, ResourceSource *source);
563  void loadResource(Resource *res);
564  void freeOldResources();
565  bool validateResource(const ResourceId &resourceId, const Common::Path &sourceMapLocation, const Common::Path &sourceName, const uint32 offset, const uint32 size, const uint32 sourceSize) const;
566  Resource *addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size = 0, const Common::Path &sourceMapLocation = Common::Path("(no map location)"));
567  Resource *updateResource(ResourceId resId, ResourceSource *src, uint32 size, const Common::Path &sourceMapLocation = Common::Path("(no map location)"));
568  Resource *updateResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size, const Common::Path &sourceMapLocation = Common::Path("(no map location)"));
569  void removeAudioResource(ResourceId resId);
570 
572  ResVersion detectMapVersion();
573  ResVersion detectVolVersion();
574 #ifdef ENABLE_SCI32
575  bool detectSci2Mac();
576 #endif
577 
583  int readResourceMapSCI0(ResourceSource *map);
584 
590  int readResourceMapSCI1(ResourceSource *map);
591 
597  int readAudioMapSCI11(IntMapResourceSource *map);
598 
605  int readAudioMapSCI1(ResourceSource *map, bool unload = false);
606 
612  void readResourcePatches();
613  void readResourcePatchesBase36();
614 
619  bool isBlacklistedPatch(const ResourceId &resId) const;
620 
621  void processPatch(ResourceSource *source, ResourceType resourceType, uint16 resourceNr, uint32 tuple = 0);
622 
626  void readWaveAudioPatches();
627  void processWavePatch(ResourceId resourceId, const Common::Path &name);
628 
632 #ifdef ENABLE_SCI32
633  void readAIFFAudioPatches();
634 #endif
635 
644  bool hasOldScriptHeader();
645 
646  void addToLRU(Resource *res);
647  void removeFromLRU(Resource *res);
648 
649  ResourceCompression getViewCompression();
650  ViewType detectViewType();
651  bool hasSci0Voc999();
652  bool hasSci1Voc900();
653  bool checkResourceDataForSignature(Resource *resource, const byte *signature);
654  bool checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2);
655  void detectSciVersion();
656 
657 public:
659  Common::Path getMacExecutableName() const;
660  bool isKoreanMessageMap(ResourceSource *source);
661 
662 private:
663  // For better or worse, because the patcher is added as a ResourceSource,
664  // its destruction is managed by freeResourceSources.
665  ResourcePatcher *_patcher;
666  bool _hasBadResources;
667 };
668 
670 public:
671  struct Channel {
672  byte number;
673  byte flags;
674  byte poly;
675  uint16 prio;
676  SciSpan<const byte> data;
677  uint16 curPos;
678  long time;
679  byte prev;
680 
681  Channel() :
682  number(0),
683  flags(0),
684  poly(0),
685  prio(0),
686  data(),
687  curPos(0) {
688  time = 0;
689  prev = 0;
690  }
691  };
692 
693  struct Track {
694  byte type;
695  byte channelCount;
696  SciSpan<const byte> header;
697  Channel *channels;
698  int16 digitalChannelNr;
699  uint16 digitalSampleRate;
700  uint16 digitalSampleSize;
701  uint16 digitalSampleStart;
702  uint16 digitalSampleEnd;
703  };
704 public:
705  SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion);
706  ~SoundResource();
707 #if 0
708  Track *getTrackByNumber(uint16 number);
709 #endif
710  Track *getTrackByType(byte type);
711  Track *getDigitalTrack();
712  int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
713 #if 0
714  byte getInitialVoiceCount(byte channel);
715 #endif
716  byte getSoundPriority() const { return _soundPriority; }
717  bool exists() const { return _resource != nullptr; }
718 
719 private:
720  SciVersion _soundVersion;
721  int _trackCount;
722  Track *_tracks;
723  Resource *_resource;
724  ResourceManager *_resMan;
725  byte _soundPriority;
726 };
727 
728 ResourceId convertPatchNameBase36(ResourceType type, const Common::String &filename);
729 
730 } // End of namespace Sci
731 
732 #endif // SCI_RESOURCE_RESOURCE_H
ResVersion _mapVersion
resource.map version
Definition: resource.h:508
uint16 _lockers
Definition: resource.h:311
Definition: str.h:59
Definition: resource.h:669
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:506
Definition: stream.h:77
int _memoryLocked
Amount of resource bytes in locked memory.
Definition: resource.h:501
SciVersion
Definition: detection.h:133
SciVersion getSciVersionForDetection()
Definition: resource.h:693
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:671
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:505
Definition: resource.h:75
Definition: resource.h:62
Definition: resource_intern.h:126
patch type + header size
Definition: resource.h:51
Definition: algorithm.h:29
Definition: fs.h:69
const char * getSciVersionDesc(SciVersion version)
Definition: resource.h:256
Definition: console.h:28
Max number of simultaneously opened volumes.
Definition: resource.h:79
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:507
Definition: util.h:251
int _memoryLRU
Amount of resource bytes under LRU control.
Definition: resource.h:502
Definition: resource_intern.h:48
Definition: resource.h:54
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:503
ResourceStatus
Definition: resource.h:58