scummvm/engines/gob/save/savehandler.cpp
D G Turner 8356656575 GOB: Replace snprintf() usage with Common::String::format()
Safer and less portability issues.
2011-06-02 02:20:51 +01:00

533 lines
12 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/endian.h"
#include "gob/gob.h"
#include "gob/save/savehandler.h"
#include "gob/save/savefile.h"
#include "gob/save/saveconverter.h"
#include "gob/global.h"
#include "gob/video.h"
#include "gob/draw.h"
#include "gob/variables.h"
#include "gob/inter.h"
namespace Gob {
SlotFile::SlotFile(GobEngine *vm, uint32 slotCount, const Common::String &base) : _vm(vm) {
_base = base;
_slotCount = slotCount;
}
SlotFile::~SlotFile() {
}
uint32 SlotFileIndexed::getSlotMax() const {
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::InSaveFile *in;
// Find the last filled save slot and base the save file size calculate on that
for (int i = (_slotCount - 1); i >= 0; i--) {
Common::String slotFile = build(i);
if (slotFile.empty())
continue;
in = saveMan->openForLoading(slotFile);
if (in) {
delete in;
return i + 1;
}
}
return 0;
}
int32 SlotFileIndexed::tallyUpFiles(uint32 slotSize, uint32 indexSize) const {
uint32 maxSlot = getSlotMax();
if (maxSlot == 0)
return -1;
return ((maxSlot * slotSize) + indexSize);
}
void SlotFileIndexed::buildIndex(byte *buffer, SavePartInfo &info,
SaveConverter *converter, bool setLongest) const {
uint32 descLength = info.getDescMaxLength();
uint32 longest = 0;
byte *bufferStart = buffer;
// Iterate over all files
for (uint32 i = 0; i < _slotCount; i++, buffer += descLength) {
Common::String slotFile = build(i);
if (!slotFile.empty()) {
char *desc = 0;
if (converter && (desc = converter->getDescription(slotFile)))
// Old style save
memcpy(buffer, desc, descLength);
else if (SaveReader::getInfo(slotFile, info))
// New style save
memcpy(buffer, info.getDesc(), descLength);
else
// No known format, fill with 0
memset(buffer, 0, descLength);
delete[] desc;
longest = MAX<uint32>(longest, strlen((const char *) buffer));
} else
// No valid slot, fill with 0
memset(buffer, 0, descLength);
}
if (setLongest) {
uint32 slot0Len;
for (slot0Len = strlen((const char *) bufferStart); slot0Len < longest; slot0Len++)
bufferStart[slot0Len] = ' ';
bufferStart[slot0Len] = '\0';
}
}
bool SlotFileIndexed::exists(int slot) const {
Common::InSaveFile *in = openRead(slot);
bool result = (in != 0);
delete in;
return result;
}
Common::InSaveFile *SlotFileIndexed::openRead(int slot) const {
Common::String name = build(slot);
if (name.empty())
return 0;
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::InSaveFile *result = saveMan->openForLoading(name);
return result;
}
Common::OutSaveFile *SlotFileIndexed::openWrite(int slot) const {
Common::String name = build(slot);
if (name.empty())
return 0;
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::OutSaveFile *result = saveMan->openForSaving(name);
return result;
}
SlotFileIndexed::SlotFileIndexed(GobEngine *vm, uint32 slotCount,
const Common::String &base, const Common::String &extStub) : SlotFile(vm, slotCount, base) {
_ext = extStub;
}
SlotFileIndexed::~SlotFileIndexed() {
}
Common::String SlotFileIndexed::build(int slot) const {
if ((slot < 0) || (((uint32) slot) >= _slotCount))
return Common::String();
Common::String buf = Common::String::format("%02d", slot);
return _base + "." + _ext + buf;
}
SlotFileStatic::SlotFileStatic(GobEngine *vm, const Common::String &base,
const Common::String &ext) : SlotFile(vm, 1, base) {
_ext = "." + ext;
}
SlotFileStatic::~SlotFileStatic() {
}
int SlotFileStatic::getSlot(int32 offset) const {
return -1;
}
int SlotFileStatic::getSlotRemainder(int32 offset) const {
return -1;
}
Common::String SlotFileStatic::build() const {
return _base + _ext;
}
bool SlotFileStatic::exists() const {
Common::InSaveFile *in = openRead();
bool result = (in != 0);
delete in;
return result;
}
Common::InSaveFile *SlotFileStatic::openRead() const {
Common::String name = build();
if (name.empty())
return 0;
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::InSaveFile *result = saveMan->openForLoading(name);
return result;
}
Common::OutSaveFile *SlotFileStatic::openWrite() const {
Common::String name = build();
if (name.empty())
return 0;
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::OutSaveFile *result = saveMan->openForSaving(name);
return result;
}
SaveHandler::SaveHandler(GobEngine *vm) : _vm(vm) {
}
SaveHandler::~SaveHandler() {
}
uint32 SaveHandler::getVarSize(GobEngine *vm) {
// Sanity checks
if (!vm || !vm->_inter || !vm->_inter->_variables)
return 0;
return vm->_inter->_variables->getSize();
}
bool SaveHandler::deleteFile() {
return true;
}
TempSpriteHandler::TempSpriteHandler(GobEngine *vm) : SaveHandler(vm) {
_sprite = 0;
}
TempSpriteHandler::~TempSpriteHandler() {
delete _sprite;
}
int32 TempSpriteHandler::getSize() {
if (!_sprite)
return -1;
return _sprite->getSize();
}
bool TempSpriteHandler::load(int16 dataVar, int32 size, int32 offset) {
if (isDummy(size))
return true;
// Sprite available?
if (!_sprite)
return false;
// Sprite requested?
if (!isSprite(size))
return false;
// Index sane?
int index = getIndex(size);
if ((index < 0) || (index >= Draw::kSpriteCount))
return false;
SurfacePtr sprite = _vm->_draw->_spritesArray[index];
// Target sprite exists?
if (!sprite)
return false;
// Load the sprite
if (!_sprite->writeSprite(*sprite))
return false;
// Handle palette
if (usesPalette(size)) {
if (!_sprite->writePalette((byte *)_vm->_global->_pPaletteDesc->vgaPal))
return false;
_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
}
if (index == 21) {
// We wrote into the backbuffer, blit
_vm->_draw->forceBlit();
_vm->_video->retrace();
} else if (index == 20)
// We wrote into the frontbuffer, retrace
_vm->_video->retrace();
return true;
}
bool TempSpriteHandler::save(int16 dataVar, int32 size, int32 offset) {
if (isDummy(size))
return true;
SurfacePtr sprite = createSprite(dataVar, size, offset);
if (!sprite)
return false;
// Save the sprite
if (!_sprite->readSprite(*sprite))
return false;
// Handle palette
if (usesPalette(size))
if (!_sprite->readPalette((const byte *)_vm->_global->_pPaletteDesc->vgaPal))
return false;
return true;
}
bool TempSpriteHandler::create(uint32 width, uint32 height, bool trueColor) {
delete _sprite;
_sprite = 0;
// Create a new temporary sprite
_sprite = new SavePartSprite(width, height, trueColor);
return true;
}
bool TempSpriteHandler::createFromSprite(int16 dataVar, int32 size, int32 offset) {
return createSprite(dataVar, size, offset) != 0;
}
SurfacePtr TempSpriteHandler::createSprite(int16 dataVar, int32 size, int32 offset) {
SurfacePtr sprt;
// Sprite requested?
if (!isSprite(size))
return sprt;
// Index sane?
int index = getIndex(size);
if ((index < 0) || (index >= Draw::kSpriteCount))
return sprt;
// Sprite exists?
if (!(sprt = _vm->_draw->_spritesArray[index]))
return sprt;
if (!create(sprt->getWidth(), sprt->getHeight(), sprt->getBPP() > 1))
sprt.reset();
return sprt;
}
// A size of 0 means no proper sprite should be saved/loaded,
// but no error should be thrown either.
bool TempSpriteHandler::isDummy(int32 size) {
return (size == 0);
}
// A negative size is the flag for using a sprite
bool TempSpriteHandler::isSprite(int32 size) {
return (size < 0);
}
// Contruct the index
int TempSpriteHandler::getIndex(int32 size) {
// Palette flag
if (size < -3000)
size += 3000;
if (size < -1000)
size += 1000;
return (-size - 1);
}
// A size smaller than -1000 indicates palette usage
bool TempSpriteHandler::usesPalette(int32 size) {
return (size < -1000);
}
NotesHandler::File::File(GobEngine *vm, const Common::String &base) :
SlotFileStatic(vm, base, "blo") {
}
NotesHandler::File::~File() {
}
NotesHandler::NotesHandler(uint32 notesSize, GobEngine *vm, const Common::String &target) :
SaveHandler(vm) {
_notesSize = notesSize;
_file = new File(vm, target);
_notes = new SavePartVars(vm, _notesSize);
}
NotesHandler::~NotesHandler() {
delete _file;
delete _notes;
}
int32 NotesHandler::getSize() {
Common::String fileName = _file->build();
if (fileName.empty())
return -1;
Common::InSaveFile *saveFile;
SaveConverter_Notes converter(_vm, _notesSize, fileName);
if (converter.isOldSave(&saveFile)) {
// Old save, get the size olden-style
int32 size = saveFile->size();
delete saveFile;
return size;
}
SaveReader reader(1, 0, fileName);
SaveHeader header;
if (!reader.load())
return -1;
if (!reader.readPartHeader(0, &header))
return -1;
// Return the part's size
return header.getSize();
}
bool NotesHandler::load(int16 dataVar, int32 size, int32 offset) {
if ((dataVar < 0) || (size < 0) || (offset < 0))
return false;
Common::String fileName = _file->build();
if (fileName.empty())
return false;
SaveReader *reader;
SaveConverter_Notes converter(_vm, _notesSize, fileName);
if (converter.isOldSave()) {
// Old save, plug the converter in
if (!converter.load())
return false;
reader = new SaveReader(1, 0, converter);
} else
// New save, load directly
reader = new SaveReader(1, 0, fileName);
SavePartVars vars(_vm, _notesSize);
if (!reader->load()) {
delete reader;
return false;
}
if (!reader->readPart(0, &vars)) {
delete reader;
return false;
}
if (!vars.writeInto(dataVar, offset, size)) {
delete reader;
return false;
}
delete reader;
return true;
}
bool NotesHandler::save(int16 dataVar, int32 size, int32 offset) {
if ((dataVar < 0) || (size < 0) || (offset < 0))
return false;
Common::String fileName = _file->build();
if (fileName.empty())
return false;
SaveWriter writer(1, 0, fileName);
SavePartVars vars(_vm, _notesSize);
if (!vars.readFrom(dataVar, offset, size))
return false;
return writer.writePart(0, &vars);
}
FakeFileHandler::FakeFileHandler(GobEngine *vm) : SaveHandler(vm) {
}
FakeFileHandler::~FakeFileHandler() {
}
int32 FakeFileHandler::getSize() {
if (_data.empty())
return -1;
return _data.size();
}
bool FakeFileHandler::load(int16 dataVar, int32 size, int32 offset) {
if (size <= 0)
return false;
if ((uint32)(offset + size) > _data.size())
return false;
_vm->_inter->_variables->copyFrom(dataVar, &_data[0] + offset, size);
return true;
}
bool FakeFileHandler::save(int16 dataVar, int32 size, int32 offset) {
if (size <= 0)
return false;
if ((uint32)(offset + size) > _data.size())
_data.resize(offset + size);
_vm->_inter->_variables->copyTo(dataVar, &_data[0] + offset, size);
return true;
}
bool FakeFileHandler::deleteFile() {
_data.clear();
return true;
}
} // End of namespace Gob