SUPERNOVA: Refactor .dat file access

This commit is contained in:
Jaromir Wysoglad 2019-07-02 20:59:32 +02:00 committed by Thierry Crozat
parent 0e31a6163d
commit 7164016b34
5 changed files with 60 additions and 195 deletions

View File

@ -36,8 +36,8 @@
namespace Supernova {
MSNImage::MSNImage(int MSPart)
: _MSPart(MSPart) {
MSNImage::MSNImage(SupernovaEngine *vm)
: _vm(vm) {
_palette = nullptr;
_encodedImage = nullptr;
_filenumber = -1;
@ -71,14 +71,14 @@ MSNImage::~MSNImage() {
bool MSNImage::init(int filenumber) {
Common::File file;
_filenumber = filenumber;
if (_MSPart == 1) {
if (_vm->_MSPart == 1) {
if (!file.open(Common::String::format("msn_data.%03d", filenumber))) {
warning("Image data file msn_data.%03d could not be read!", filenumber);
return false;
}
loadStream(file);
}
else if (_MSPart == 2) {
else if (_vm->_MSPart == 2) {
if (!loadFromEngineDataFile()) {
if (!file.open(Common::String::format("ms2_data.%03d", filenumber))) {
warning("Image data file ms2_data.%03d could not be read!", filenumber);
@ -93,125 +93,38 @@ bool MSNImage::init(int filenumber) {
bool MSNImage::loadPbmFromEngineDataFile() {
Common::String name;
Common::File f;
char id[5], lang[5];
id[4] = lang[4] = '\0';
if (_MSPart == 2)
if (_vm->_MSPart == 2)
return false;
if (_filenumber == 1)
name = "IMG1";
else if (_filenumber == 2)
name = "IMG2";
else
return false;
if (!f.open(SUPERNOVA_DAT))
Common::SeekableReadStream *stream = _vm->getBlockFromDatFile(name);
if (stream == nullptr)
return false;
f.read(id, 3);
if (strncmp(id, "MSN", 3) != 0)
return false;
int version = f.readByte();
if (version != SUPERNOVA_DAT_VERSION)
return false;
Common::String cur_lang = ConfMan.get("language");
// Note: we don't print any warning or errors here if we cannot find the file
// or the format is not as expected. We will get those warning when reading the
// strings anyway (actually the engine will even refuse to start).
int part;
uint32 gameBlockSize;
while (!f.eos()) {
part = f.readByte();
gameBlockSize = f.readUint32LE();
if (f.eos()){
return false;
}
if (part == _MSPart) {
break;
} else
f.skip(gameBlockSize);
}
uint32 readSize = 0;
while (readSize < gameBlockSize) {
f.read(id, 4);
f.read(lang, 4);
uint32 size = f.readUint32LE();
if (f.eos())
break;
if (name == id && cur_lang == lang) {
return f.read(_encodedImage, size) == size;
} else {
f.skip(size);
readSize += size;
}
}
return false;
stream->read(_encodedImage, stream->size());
return true;
}
bool MSNImage::loadFromEngineDataFile() {
Common::String name;
Common::File f;
char id[5], lang[5];
id[4] = lang[4] = '\0';
if (_MSPart == 1) {
if (_vm->_MSPart == 1) {
return false;
} else if (_MSPart == 2) {
} else if (_vm->_MSPart == 2) {
if (_filenumber == 15)
name = "M015";
else if (_filenumber == 28)
name = "M028";
else
return false;
if (!f.open(SUPERNOVA_DAT))
return false;
f.read(id, 3);
if (strncmp(id, "MSN", 3) != 0)
return false;
int version = f.readByte();
if (version != SUPERNOVA_DAT_VERSION)
return false;
}
Common::String cur_lang = ConfMan.get("language");
int part;
uint32 gameBlockSize;
while (!f.eos()) {
part = f.readByte();
gameBlockSize = f.readUint32LE();
if (f.eos()){
return false;
}
if (part == _MSPart) {
break;
} else
f.skip(gameBlockSize);
}
uint32 readSize = 0;
while (readSize < gameBlockSize) {
f.read(id, 4);
f.read(lang, 4);
uint32 size = f.readUint32LE();
if (f.eos())
break;
if (name == id && cur_lang == lang) {
return loadStream(*f.readStream(size));
} else {
f.skip(size);
readSize += size;
}
}
return false;
Common::SeekableReadStream *stream = _vm->getBlockFromDatFile(name);
if (stream == nullptr)
return false;
return loadStream(*stream);
}
bool MSNImage::loadStream(Common::SeekableReadStream &stream) {
@ -312,8 +225,8 @@ bool MSNImage::loadStream(Common::SeekableReadStream &stream) {
}
bool MSNImage::loadSections() {
bool isNewspaper = (_MSPart == 1 && (_filenumber == 1 || _filenumber == 2)) ||
(_MSPart == 2 && _filenumber == 38);
bool isNewspaper = (_vm->_MSPart == 1 && (_filenumber == 1 || _filenumber == 2)) ||
(_vm->_MSPart == 2 && _filenumber == 38);
int imageWidth = isNewspaper ? 640 : 320;
int imageHeight = isNewspaper ? 480 : 200;
_pitch = imageWidth;

View File

@ -25,6 +25,7 @@
#include "common/scummsys.h"
#include "image/image_decoder.h"
#include "supernova/supernova.h"
namespace Common {
class SeekableReadStream;
@ -35,10 +36,11 @@ struct Surface;
}
namespace Supernova {
class SupernovaEngine;
class MSNImage : public Image::ImageDecoder {
public:
MSNImage(int MSPart);
MSNImage(SupernovaEngine *vm);
virtual ~MSNImage();
virtual void destroy();
@ -79,7 +81,7 @@ public:
} _clickField[kMaxClickFields];
private:
int _MSPart;
SupernovaEngine *_vm;
bool loadFromEngineDataFile();
bool loadPbmFromEngineDataFile();
bool loadSections();

View File

@ -114,22 +114,22 @@ static const byte mouseWait[64] = {
};
ResourceManager::ResourceManager(int MSPart)
ResourceManager::ResourceManager(SupernovaEngine *vm)
: _audioRate(11931)
, _MSPart(MSPart) {
if (MSPart == 1)
, _vm(vm) {
if (_vm->_MSPart == 1)
_soundSamples = new Common::ScopedPtr<Audio::SeekableAudioStream>[kAudioNumSamples1];
else if (MSPart == 2)
else if (_vm->_MSPart == 2)
_soundSamples = new Common::ScopedPtr<Audio::SeekableAudioStream>[kAudioNumSamples2];
initGraphics();
}
ResourceManager::~ResourceManager() {
if (_MSPart == 1) {
if (_vm->_MSPart == 1) {
for (int i = 0; i < 44; i++)
delete _images[i];
}
if (_MSPart == 2) {
if (_vm->_MSPart == 2) {
for (int i = 0; i < 47; i++)
delete _images[i];
}
@ -140,9 +140,9 @@ ResourceManager::~ResourceManager() {
void ResourceManager::initGraphics() {
Screen::initPalette();
initCursorGraphics();
if (_MSPart == 1)
if (_vm->_MSPart == 1)
initImages1();
else if (_MSPart == 2)
else if (_vm->_MSPart == 2)
initImages2();
}
@ -238,18 +238,18 @@ void ResourceManager::loadSound2(AudioId id) {
}
void ResourceManager::loadImage(int filenumber) {
if (_MSPart == 1) {
if (_vm->_MSPart == 1) {
if (filenumber < 44) {
_images[filenumber] = new MSNImage(_MSPart);
_images[filenumber] = new MSNImage(_vm);
if (!_images[filenumber]->init(filenumber))
error("Failed reading image file msn_data.%03d", filenumber);
} else {
_images[44] = new MSNImage(_MSPart);
_images[44] = new MSNImage(_vm);
if (!_images[44]->init(filenumber))
error("Failed reading image file msn_data.%03d", filenumber);
}
} else if (_MSPart == 2) {
_images[filenumber] = new MSNImage(_MSPart);
} else if (_vm->_MSPart == 2) {
_images[filenumber] = new MSNImage(_vm);
if (!_images[filenumber]->init(filenumber))
error("Failed reading image file ms2_data.%03d", filenumber);
}
@ -257,9 +257,9 @@ void ResourceManager::loadImage(int filenumber) {
Audio::SeekableAudioStream *ResourceManager::getSoundStream(AudioId index) {
if (!_soundSamples[index]) {
if (_MSPart == 1)
if (_vm->_MSPart == 1)
loadSound1(index);
else if (_MSPart == 2)
else if (_vm->_MSPart == 2)
loadSound2(index);
}
Audio::SeekableAudioStream *stream;
@ -273,9 +273,9 @@ Audio::AudioStream *ResourceManager::getSoundStream(MusicId index) {
switch (index) {
case kMusicIntro:
if (!_musicIntroBuffer) {
if (_MSPart == 1)
if (_vm->_MSPart == 1)
_musicIntroBuffer.reset(convertToMod("msn_data.052", 1));
else if (_MSPart == 2)
else if (_vm->_MSPart == 2)
_musicIntroBuffer.reset(convertToMod("ms2_data.052", 2));
}
_musicIntro.reset(Audio::makeProtrackerStream(_musicIntroBuffer.get()));
@ -284,9 +284,9 @@ Audio::AudioStream *ResourceManager::getSoundStream(MusicId index) {
// fall through
case kMusicOutro:
if (!_musicOutroBuffer) {
if (_MSPart == 1)
if (_vm->_MSPart == 1)
_musicOutroBuffer.reset(convertToMod("msn_data.049", 1));
else if (_MSPart == 2)
else if (_vm->_MSPart == 2)
_musicOutroBuffer.reset(convertToMod("ms2_data.056", 2));
}
_musicOutro.reset(Audio::makeProtrackerStream(_musicOutroBuffer.get()));
@ -304,9 +304,9 @@ Audio::AudioStream *ResourceManager::getSirenStream() {
MSNImage *ResourceManager::getImage(int filenumber) {
//check array boundaries
if (_MSPart == 1 && filenumber > 43 && filenumber != 55)
if (_vm->_MSPart == 1 && filenumber > 43 && filenumber != 55)
return nullptr;
if (_MSPart == 2 && filenumber > 46)
if (_vm->_MSPart == 2 && filenumber > 46)
return nullptr;
if (filenumber == 55) {

View File

@ -29,6 +29,7 @@
#include "supernova/graphics.h"
#include "supernova/sound.h"
#include "supernova/supernova.h"
namespace Common {
@ -36,6 +37,7 @@ class MemoryReadStream;
}
namespace Supernova {
class SupernovaEngine;
class ResourceManager {
public:
@ -49,7 +51,7 @@ public:
static const int kNumImageFiles2 = 47;
public:
ResourceManager(int MSPart);
ResourceManager(SupernovaEngine *vm);
~ResourceManager();
Audio::SeekableAudioStream *getSoundStream(AudioId index);
@ -77,7 +79,7 @@ private:
Common::ScopedPtr<Audio::AudioStream> _musicIntro;
Common::ScopedPtr<Audio::AudioStream> _musicOutro;
Common::ScopedPtr<Audio::AudioStream> _sirenStream;
int _MSPart;
SupernovaEngine *_vm;
int _audioRate;
MSNImage **_images;
byte _cursorNormal[256];

View File

@ -148,7 +148,7 @@ void SupernovaEngine::init() {
if (status.getCode() != Common::kNoError)
error("Failed reading game strings");
_resMan = new ResourceManager(_MSPart);
_resMan = new ResourceManager(this);
_sound = new Sound(_mixer, _resMan);
_screen = new Screen(this, _resMan);
if (_MSPart == 1)
@ -185,78 +185,26 @@ void SupernovaEngine::pauseEngineIntern(bool pause) {
}
Common::Error SupernovaEngine::loadGameStrings() {
Common::String cur_lang = ConfMan.get("language");
Common::String string_id("TEXT");
// Note: we don't print any warning or errors here if we cannot find the file
// or the format is not as expected. We will get those warning when reading the
// strings anyway (actually the engine will even refuse to start).
Common::SeekableReadStream *stream = getBlockFromDatFile(string_id);
// Validate the data file header
Common::File f;
char id[5], lang[5];
id[4] = lang[4] = '\0';
if (!f.open(SUPERNOVA_DAT)) {
GUIErrorMessageFormat(_("Unable to locate the '%s' engine data file."), SUPERNOVA_DAT);
return Common::kReadingFailed;
}
f.read(id, 3);
if (strncmp(id, "MSN", 3) != 0) {
GUIErrorMessageFormat(_("The '%s' engine data file is corrupt."), SUPERNOVA_DAT);
if (stream == nullptr) {
Common::Language l = Common::parseLanguage(ConfMan.get("language"));
GUIErrorMessageFormat(_("Unable to locate the text for %s language in engine data file."), Common::getLanguageDescription(l));
return Common::kReadingFailed;
}
int version = f.readByte();
if (version != SUPERNOVA_DAT_VERSION) {
GUIErrorMessageFormat(
_("Incorrect version of the '%s' engine data file found. Expected %d but got %d."),
SUPERNOVA_DAT, SUPERNOVA_DAT_VERSION, version);
return Common::kReadingFailed;
int size = stream->size();
while (size > 0) {
Common::String s;
char ch;
while ((ch = (char)stream->readByte()) != '\0')
s += ch;
_gameStrings.push_back(s);
size -= s.size() + 1;
}
int part;
uint32 gameBlockSize;
while (!f.eos()) {
part = f.readByte();
gameBlockSize = f.readUint32LE();
if (f.eos()){
GUIErrorMessageFormat(_("Unable to find block for part %d"), _MSPart);
return Common::kReadingFailed;
}
if (part == _MSPart) {
break;
} else
f.skip(gameBlockSize);
}
uint32 readSize = 0;
while (readSize < gameBlockSize) {
f.read(id, 4);
f.read(lang, 4);
uint32 size = f.readUint32LE();
if (f.eos())
break;
if (string_id == id && cur_lang == lang) {
while (size > 0) {
Common::String s;
char ch;
while ((ch = (char)f.readByte()) != '\0')
s += ch;
_gameStrings.push_back(s);
size -= s.size() + 1;
}
return Common::kNoError;
} else {
f.skip(size);
readSize += size;
}
}
Common::Language l = Common::parseLanguage(cur_lang);
GUIErrorMessageFormat(_("Unable to locate the text for %s language in engine data file."), Common::getLanguageDescription(l));
return Common::kReadingFailed;
return Common::kNoError;
}
const Common::String &SupernovaEngine::getGameString(int idx) const {