/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef AGI_LOADER_H #define AGI_LOADER_H namespace Agi { class AgiLoader { public: AgiLoader(AgiEngine *vm) : _vm(vm) {} virtual ~AgiLoader() {} /** * Performs one-time initializations, such as locating files * with dynamic names. */ virtual void init() {} /** * Loads all AGI directory entries from disk and and populates * the AgiDir arrays in AgiGame with them. */ virtual int loadDirs() = 0; /** * Loads a volume resource from disk. */ virtual uint8 *loadVolumeResource(AgiDir *agid) = 0; /** * Loads AgiEngine::_objects from disk. */ virtual int loadObjects() = 0; /** * Loads AgiBase::_words from disk. */ virtual int loadWords() = 0; protected: AgiEngine *_vm; typedef Common::HashMap FileMap; static void getPotentialDiskImages( const char * const *imageExtensions, size_t imageExtensionCount, Common::Array &imageFiles, FileMap &fileMap); }; struct AgiDiskVolume { uint32 disk; uint32 offset; AgiDiskVolume() : disk(_EMPTY), offset(0) {} AgiDiskVolume(uint32 d, uint32 o) : disk(d), offset(o) {} }; /** * Apple II version of the format for LOGDIR, VIEWDIR, etc. * See AgiLoader_A2::loadDir for more details. */ enum A2DirVersion { A2DirVersionOld, // 4 bits for volume, 8 for track A2DirVersionNew, // 5 bits for volume, 7 for track }; class AgiLoader_A2 : public AgiLoader { public: AgiLoader_A2(AgiEngine *vm) : AgiLoader(vm) {} ~AgiLoader_A2() override; void init() override; int loadDirs() override; uint8 *loadVolumeResource(AgiDir *agid) override; int loadObjects() override; int loadWords() override; private: Common::Array _disks; Common::Array _volumes; AgiDir _logDir; AgiDir _picDir; AgiDir _viewDir; AgiDir _soundDir; AgiDir _objects; AgiDir _words; int readDiskOne(Common::SeekableReadStream &stream, Common::Array &volumeMap); static bool readInitDir(Common::SeekableReadStream &stream, byte index, AgiDir &agid); static bool readDir(Common::SeekableReadStream &stream, int position, AgiDir &agid); static bool readVolumeMap(Common::SeekableReadStream &stream, uint32 position, uint32 bufferLength, Common::Array &volumeMap); A2DirVersion detectDirVersion(Common::SeekableReadStream &stream) const; static bool loadDir(AgiDir *dir, Common::SeekableReadStream &disk, uint32 dirOffset, uint32 dirLength, A2DirVersion dirVersion); }; class AgiLoader_v1 : public AgiLoader { public: AgiLoader_v1(AgiEngine *vm) : AgiLoader(vm) {} void init() override; int loadDirs() override; uint8 *loadVolumeResource(AgiDir *agid) override; int loadObjects() override; int loadWords() override; private: Common::Array _imageFiles; Common::Array _volumes; AgiDir _logDir; AgiDir _picDir; AgiDir _viewDir; AgiDir _soundDir; AgiDir _objects; AgiDir _words; bool readDiskOneV1(Common::SeekableReadStream &stream); bool readDiskOneV2001(Common::SeekableReadStream &stream, int &vol0Offset); static bool readInitDirV1(Common::SeekableReadStream &stream, byte index, AgiDir &agid); static bool readInitDirV2001(Common::SeekableReadStream &stream, byte index, AgiDir &agid); bool loadDir(AgiDir *dir, Common::File &disk, uint32 dirOffset, uint32 dirLength); }; class AgiLoader_v2 : public AgiLoader { private: bool _hasV3VolumeFormat; int loadDir(AgiDir *agid, const char *fname); bool detectV3VolumeFormat(); public: AgiLoader_v2(AgiEngine *vm) : _hasV3VolumeFormat(false), AgiLoader(vm) {} int loadDirs() override; uint8 *loadVolumeResource(AgiDir *agid) override; int loadObjects() override; int loadWords() override; }; class AgiLoader_v3 : public AgiLoader { private: Common::String _name; /**< prefix in directory and/or volume file names (`GR' for goldrush) */ int loadDir(AgiDir *agid, Common::File *fp, uint32 offs, uint32 len); public: AgiLoader_v3(AgiEngine *vm) : AgiLoader(vm) {} void init() override; int loadDirs() override; uint8 *loadVolumeResource(AgiDir *agid) override; int loadObjects() override; int loadWords() override; }; class GalLoader : public AgiLoader { public: GalLoader(AgiEngine *vm) : _dirOffset(0), AgiLoader(vm) {} void init() override; int loadDirs() override; uint8 *loadVolumeResource(AgiDir *agid) override; int loadObjects() override; int loadWords() override; private: Common::String _imageFile; int _dirOffset; static bool isDirectory(Common::SeekableReadStream &stream, uint32 dirOffset); static uint32 readDirectoryEntry(Common::SeekableReadStream &stream, uint32 *sectorCount); }; class GalLoader_A2 : public AgiLoader { public: GalLoader_A2(AgiEngine *vm) : AgiLoader(vm) {} ~GalLoader_A2(); void init() override; int loadDirs() override; uint8 *loadVolumeResource(AgiDir *agid) override; int loadObjects() override; int loadWords() override; private: Common::Array _disks; static bool readDiskOne(Common::SeekableReadStream &disk, AgiDir *logicDir); static bool readDirectoryEntry(Common::SeekableReadStream &stream, AgiDir &dirEntry); static bool validateDisk(Common::SeekableReadStream &disk, byte diskIndex, AgiDir *logicDir); static bool loadDir(AgiDir *dir, Common::SeekableReadStream &disk, uint32 dirOffset, uint32 dirCount); }; } // End of namespace Agi #endif /* AGI_LOADER_H */