scummvm/engines/adl/disk.h
2019-07-17 11:42:23 +02:00

201 lines
5.7 KiB
C++

/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/ptr.h"
#include "common/file.h"
#include "common/debug.h"
#ifndef ADL_DISK_H
#define ADL_DISK_H
namespace Common {
class SeekableReadStream;
class String;
}
namespace Adl {
// Used for disk image detection
int32 computeMD5(const Common::FSNode &node, Common::String &md5, uint32 md5Bytes);
class DataBlock {
public:
virtual ~DataBlock() { }
virtual Common::SeekableReadStream *createReadStream() const = 0;
};
typedef Common::SharedPtr<DataBlock> DataBlockPtr;
typedef Common::ScopedPtr<Common::SeekableReadStream> StreamPtr;
class Files {
public:
virtual ~Files() { }
virtual const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const = 0;
virtual Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const = 0;
protected:
class DataBlock : public Adl::DataBlock {
public:
DataBlock(const Files *files, const Common::String &filename, uint offset) :
_files(files),
_filename(filename),
_offset(offset) { }
Common::SeekableReadStream *createReadStream() const override {
return _files->createReadStream(_filename, _offset);
}
private:
const Common::String _filename;
uint _offset;
const Files *_files;
};
};
class DiskImage {
public:
DiskImage() :
_stream(nullptr),
_tracks(0),
_sectorsPerTrack(0),
_bytesPerSector(0),
_sectorLimit(0),
_firstSector(0) { }
~DiskImage() {
delete _stream;
}
bool open(const Common::String &filename);
const DataBlockPtr getDataBlock(uint track, uint sector, uint offset = 0, uint size = 0) const;
Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0, uint sectorsUsed = 0) const;
void setSectorLimit(uint sectorLimit) { _sectorLimit = sectorLimit; } // Maximum number of sectors to read per track before stepping
uint getBytesPerSector() const { return _bytesPerSector; }
uint getSectorsPerTrack() const { return _sectorsPerTrack; }
uint getTracks() const { return _tracks; }
protected:
class DataBlock : public Adl::DataBlock {
public:
DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size, uint sectorLimit) :
_track(track),
_sector(sector),
_offset(offset),
_size(size),
_sectorLimit(sectorLimit),
_disk(disk) { }
Common::SeekableReadStream *createReadStream() const override {
return _disk->createReadStream(_track, _sector, _offset, _size, _sectorLimit);
}
private:
uint _track, _sector, _offset, _size;
uint _sectorLimit;
const DiskImage *_disk;
};
Common::SeekableReadStream *_stream;
uint _tracks, _sectorsPerTrack, _bytesPerSector, _firstSector;
uint _sectorLimit;
};
// Data in plain files
class Files_Plain : public Files {
public:
const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const override;
Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const override;
};
// Data in files contained in Apple DOS 3.3 disk image
class Files_AppleDOS : public Files {
public:
Files_AppleDOS();
~Files_AppleDOS();
bool open(const Common::String &filename, uint trackVTOC = 17);
const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const override;
Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const override;
private:
enum FileType {
kFileTypeText = 0,
kFileTypeAppleSoft = 2,
kFileTypeBinary = 4
};
enum {
kSectorSize = 256,
kFilenameLen = 30
};
struct TrackSector {
byte track;
byte sector;
};
struct TOCEntry {
byte type;
uint16 totalSectors;
Common::Array<TrackSector> sectors;
};
void readVTOC(uint trackVTOC);
void readSectorList(TrackSector start, Common::Array<TrackSector> &list);
Common::SeekableReadStream *createReadStreamText(const TOCEntry &entry) const;
Common::SeekableReadStream *createReadStreamBinary(const TOCEntry &entry) const;
DiskImage *_disk;
Common::HashMap<Common::String, TOCEntry> _toc;
};
// On the Apple II, sector headers contain a disk volume number. This number
// is used by ADL multi-disk games. The PC port has the disk volume number
// as the first data byte of every sector that contains game data. We need
// to skip this number as we read in the data. Additionally, the data is now
// prefixed with an uint16 containing the data size.
class DataBlock_PC : public DataBlock {
public:
DataBlock_PC(DiskImage *disk, byte track, byte sector, uint16 offset = 0) :
_disk(disk),
_track(track),
_sector(sector),
_offset(offset) { }
virtual ~DataBlock_PC() { }
Common::SeekableReadStream *createReadStream() const override;
private:
void read(Common::SeekableReadStream &stream, byte *const dataPtr, const uint32 size) const;
DiskImage *_disk;
byte _track, _sector;
uint16 _offset;
};
} // End of namespace Adl
#endif