diff options
author | uruk | 2014-04-26 08:02:00 +0200 |
---|---|---|
committer | uruk | 2014-04-26 08:02:00 +0200 |
commit | b58965e4e62259fc000dd731f694a24244268983 (patch) | |
tree | a08ed7b77927adaa7c6bf354566d34c85d454fe0 | |
parent | aad77304a8727ba1d2a1b802a95c7f8085d50853 (diff) | |
download | scummvm-rg350-b58965e4e62259fc000dd731f694a24244268983.tar.gz scummvm-rg350-b58965e4e62259fc000dd731f694a24244268983.tar.bz2 scummvm-rg350-b58965e4e62259fc000dd731f694a24244268983.zip |
CGE2: Add file I/O.
-rw-r--r-- | engines/cge2/cge2.cpp | 6 | ||||
-rw-r--r-- | engines/cge2/cge2.h | 5 | ||||
-rw-r--r-- | engines/cge2/fileio.cpp | 247 | ||||
-rw-r--r-- | engines/cge2/fileio.h | 120 | ||||
-rw-r--r-- | engines/cge2/module.mk | 3 |
5 files changed, 380 insertions, 1 deletions
diff --git a/engines/cge2/cge2.cpp b/engines/cge2/cge2.cpp index 0b06cd0fb4..8f84f5e31a 100644 --- a/engines/cge2/cge2.cpp +++ b/engines/cge2/cge2.cpp @@ -31,11 +31,16 @@ namespace CGE2 { CGE2Engine::CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription) : Engine(syst), _gameDescription(gameDescription) { + _resman = nullptr; } CGE2Engine::~CGE2Engine() { } +void CGE2Engine::init() { + _resman = new ResourceManager(); +} + bool CGE2Engine::hasFeature(EngineFeature f) const { return false; } @@ -58,6 +63,7 @@ Common::Error CGE2Engine::saveGameState(int slot, const Common::String &desc) { } Common::Error CGE2Engine::run() { + init(); warning("STUB: CGE2Engine::run()"); return Common::kNoError; } diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h index ee4ecf62b1..068b371ff6 100644 --- a/engines/cge2/cge2.h +++ b/engines/cge2/cge2.h @@ -30,6 +30,7 @@ #include "engines/engine.h" #include "engines/advancedDetector.h" +#include "cge2/fileio.h" namespace CGE2 { @@ -45,6 +46,10 @@ public: virtual Common::Error run(); const ADGameDescription *_gameDescription; + + ResourceManager *_resman; +private: + void init(); }; } // End of namespace CGE2 diff --git a/engines/cge2/fileio.cpp b/engines/cge2/fileio.cpp new file mode 100644 index 0000000000..4da2c52cfa --- /dev/null +++ b/engines/cge2/fileio.cpp @@ -0,0 +1,247 @@ +/* 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. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/system.h" +#include "common/str.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/memstream.h" +#include "cge2/cge2.h" +#include "cge2/fileio.h" + +namespace CGE2 { + +/*----------------------------------------------------------------------- + * BtPage + *-----------------------------------------------------------------------*/ +void BtPage::readBTree(Common::ReadStream &s) { + _header._count = s.readUint16LE(); + _header._down = s.readUint16LE(); + + if (_header._down == kBtValNone) { + // Leaf list + for (int i = 0; i < kBtLeafCount; ++i) { + s.read(_leaf[i]._key, kBtKeySize); + _leaf[i]._pos = s.readUint32LE(); + _leaf[i]._size = s.readUint32LE(); + } + } else { + // Root index + for (int i = 0; i < kBtInnerCount; ++i) { + s.read(_inner[i]._key, kBtKeySize); + _inner[i]._down = s.readUint16LE(); + } + } +} + +/*----------------------------------------------------------------------- + * ResourceManager + *-----------------------------------------------------------------------*/ +ResourceManager::ResourceManager() { + _datFile = new Common::File(); + _datFile->open(kDatName); + + _catFile = new Common::File(); + _catFile->open(kCatName); + + if (!_datFile->isOpen() || !_catFile->isOpen()) + error("Unable to open data files"); + + for (int i = 0; i < kBtLevel; i++) { + _buff[i]._page = new BtPage; + _buff[i]._pageNo = kBtValNone; + _buff[i]._index = -1; + assert(_buff[i]._page != NULL); + } +} + +ResourceManager::~ResourceManager() { + _datFile->close(); + delete _datFile; + + _catFile->close(); + delete _catFile; + + for (int i = 0; i < kBtLevel; i++) + delete _buff[i]._page; +} + +void ResourceManager::XCrypt(byte *buf, uint16 length) { + byte *b = buf; + + for (uint16 i = 0; i < length; i++) + *b++ ^= kCryptSeed; +} + +bool ResourceManager::seek(int32 offs, int whence) { + return _datFile->seek(offs, whence); +} + +uint16 ResourceManager::read(byte *buf, uint16 length) { + if (!_datFile->isOpen()) + return 0; + + uint16 bytesRead = _datFile->read(buf, length); + if (!bytesRead) + error("Read %s - %d bytes", _datFile->getName(), length); + XCrypt(buf, length); + return bytesRead; +} + +BtPage *ResourceManager::getPage(int level, uint16 pageId) { + if (_buff[level]._pageNo != pageId) { + int32 pos = pageId * kBtSize; + _buff[level]._pageNo = pageId; + assert(_catFile->size() > pos); + // In the original, there was a check verifying if the + // purpose was to write a new file. This should only be + // to create a new file, thus it was removed. + _catFile->seek(pageId * kBtSize, SEEK_SET); + + // Read in the page + byte buffer[kBtSize]; + int bytesRead = catRead(buffer, kBtSize); + + // Unpack it into the page structure + Common::MemoryReadStream stream(buffer, bytesRead, DisposeAfterUse::NO); + _buff[level]._page->readBTree(stream); + _buff[level]._index = -1; + } + return _buff[level]._page; +} + +BtKeypack *ResourceManager::find(const char *key) { + int lev = 0; + uint16 nxt = kBtValRoot; + while (!_catFile->eos()) { + BtPage *pg = getPage(lev, nxt); + // search + if (pg->_header._down != kBtValNone) { + int i; + for (i = 0; i < pg->_header._count; i++) { + // Does this work, or does it have to compare the entire buffer? + if (scumm_strnicmp((const char *)key, (const char*)pg->_inner[i]._key, kBtKeySize) < 0) + break; + } + nxt = (i) ? pg->_inner[i - 1]._down : pg->_header._down; + _buff[lev]._index = i - 1; + lev++; + } else { + int i; + for (i = 0; i < pg->_header._count - 1; i++) { + if (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) <= 0) + break; + } + _buff[lev]._index = i; + return &pg->_leaf[i]; + } + } + return NULL; +} + +bool ResourceManager::exist(const char *name) { + return scumm_stricmp(find(name)->_key, name) == 0; +} + +uint16 ResourceManager::catRead(byte *buf, uint16 length) { + if (!_catFile->isOpen()) + return 0; + + uint16 bytesRead = _catFile->read(buf, length); + if (!bytesRead) + error("Read %s - %d bytes", _catFile->getName(), length); + XCrypt(buf, length); + return bytesRead; +} + +/*----------------------------------------------------------------------- + * EncryptedStream + *-----------------------------------------------------------------------*/ +EncryptedStream::EncryptedStream(CGE2Engine *vm, const char *name) : _vm(vm) { + _error = false; + BtKeypack *kp = _vm->_resman->find(name); + if (scumm_stricmp(kp->_key, name) != 0) + _error = true; + + _vm->_resman->seek(kp->_pos); + byte *dataBuffer; + int bufSize; + + if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) { + // SPR files have some inconsistencies. Some have extra 0x1A at the end, some others + // do not have a carriage return at the end of the last line + // Therefore, we remove this ending 0x1A and add extra new lines. + // This fixes bug #3537527 + dataBuffer = (byte *)malloc(kp->_size + 2); + _vm->_resman->read(dataBuffer, kp->_size); + if (dataBuffer[kp->_size - 1] == 0x1A) + dataBuffer[kp->_size - 1] = '\n'; + dataBuffer[kp->_size] = '\n'; + dataBuffer[kp->_size + 1] = '\n'; + bufSize = kp->_size + 2; + } else { + dataBuffer = (byte *)malloc(kp->_size); + _vm->_resman->read(dataBuffer, kp->_size); + bufSize = kp->_size; + } + + _readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES); +} + +uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) { + return _readStream->read(dataPtr, dataSize); +} + +bool EncryptedStream::err() { + return (_error & _readStream->err()); +} + +bool EncryptedStream::eos() { + return _readStream->eos(); +} + +bool EncryptedStream::seek(int32 offset) { + return _readStream->seek(offset); +} + +Common::String EncryptedStream::readLine() { + return _readStream->readLine(); +} + +int32 EncryptedStream::size() { + return _readStream->size(); +} + +int32 EncryptedStream::pos() { + return _readStream->pos(); +} + +EncryptedStream::~EncryptedStream() { + delete _readStream; +} + +} // End of namespace CGE2 diff --git a/engines/cge2/fileio.h b/engines/cge2/fileio.h new file mode 100644 index 0000000000..42bb2ee352 --- /dev/null +++ b/engines/cge2/fileio.h @@ -0,0 +1,120 @@ +/* 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. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_FILEIO_H +#define CGE2_FILEIO_H + +#include "common/file.h" + +namespace CGE2 { + +class CGE2Engine; + +#define kBtSize 2048 +#define kBtKeySize 13 +#define kBtLevel 2 +#define kBtInnerCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 2 /*sizeof(Inner) */)) +#define kBtLeafCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 4 + 4 /*sizeof(BtKeypack) */)) +#define kBtValNone 0xFFFF +#define kBtValRoot 0 +#define kCatName "VOL.CAT" +#define kDatName "VOL.DAT" +#define kCryptSeed 0xA5 + +struct BtKeypack { + char _key[kBtKeySize]; + uint32 _pos; + uint32 _size; +}; + +struct Inner { + uint8 _key[kBtKeySize]; + uint16 _down; +}; + +struct Header { + uint16 _count; + uint16 _down; +}; + +struct BtPage { + Header _header; + union { + // dummy filler to make proper size of union + uint8 _data[kBtSize - 4]; /* 4 is the size of struct Header */ + // inner version of data: key + word-sized page link + Inner _inner[kBtInnerCount]; + // leaf version of data: key + all user data + BtKeypack _leaf[kBtLeafCount]; + }; + + void readBTree(Common::ReadStream &s); +}; + +class ResourceManager { +private: + struct { + BtPage *_page; + uint16 _pageNo; + int _index; + } _buff[kBtLevel]; + + BtPage *getPage(int level, uint16 pageId); + uint16 catRead(byte *buf, uint16 length); + Common::File *_catFile; + Common::File *_datFile; + void XCrypt(byte *buf, uint16 length); +public: + ResourceManager(); + ~ResourceManager(); + uint16 read(byte *buf, uint16 length); + bool seek(int32 offs, int whence = SEEK_SET); + + BtKeypack *find(const char *key); + bool exist(const char *name); +}; + +class EncryptedStream { +private: + CGE2Engine *_vm; + Common::SeekableReadStream *_readStream; + bool _error; +public: + EncryptedStream(CGE2Engine *vm, const char *name); + ~EncryptedStream(); + bool err(); + bool eos(); + bool seek(int32 offset); + int32 pos(); + int32 size(); + uint32 read(byte *dataPtr, uint32 dataSize); + Common::String readLine(); +}; + +} // End of namespace CGE2 + +#endif // CGE2_FILEIO_H diff --git a/engines/cge2/module.mk b/engines/cge2/module.mk index 75f2743286..fc710b663a 100644 --- a/engines/cge2/module.mk +++ b/engines/cge2/module.mk @@ -2,7 +2,8 @@ MODULE := engines/cge2 MODULE_OBJS = \ cge2.o \ - detection.o + detection.o \ + fileio.o # This module can be built as a plugin ifeq ($(ENABLE_CGE2), DYNAMIC_PLUGIN) |