scummvm/engines/sludge/savedata.cpp

236 lines
6.1 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/savefile.h"
#include "sludge/allfiles.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/savedata.h"
#include "sludge/variable.h"
#define LOAD_ERROR "Can't load custom data...\n\n"
namespace Sludge {
const char CustomSaveHelper::UTF8_CHECKER[] = {'U', 'N', '\xef', '\xbf', '\xbd', 'L', 'O', '\xef', '\xbf', '\xbd', 'C', 'K', 'E', 'D', '\0'};
uint16 CustomSaveHelper::_saveEncoding = false;
char CustomSaveHelper::_encode1 = 0;
char CustomSaveHelper::_encode2 = 0;
void CustomSaveHelper::writeStringEncoded(const Common::String checker, Common::WriteStream *stream) {
int len = checker.size();
stream->writeUint16BE(len);
for (int a = 0; a < len; a++) {
stream->writeByte(checker[a] ^ _encode1);
_encode1 += _encode2;
}
}
Common::String CustomSaveHelper::readStringEncoded(Common::SeekableReadStream *fp) {
int len = fp->readUint16BE();
Common::String res = "";
for (int a = 0; a < len; a++) {
res += (char)(fp->readByte() ^ _encode1);
_encode1 += _encode2;
}
return res;
}
char *CustomSaveHelper::readTextPlain(Common::SeekableReadStream *fp) {
int32 startPos;
uint32 stringSize = 0;
bool keepGoing = true;
char gotChar;
char *reply;
startPos = fp->pos();
while (keepGoing) {
gotChar = (char)fp->readByte();
if ((gotChar == '\n') || (fp->eos())) {
keepGoing = false;
} else {
stringSize++;
}
}
if ((stringSize == 0) && (fp->eos())) {
return NULL;
} else {
fp->seek(startPos, SEEK_SET);
reply = new char[stringSize + 1];
if (reply == NULL)
return NULL;
uint bytes_read = fp->read(reply, stringSize);
if (bytes_read != stringSize && fp->err()) {
warning("Reading error in readTextPlain.");
}
fp->readByte(); // Skip the newline character
reply[stringSize] = 0;
}
return reply;
}
bool CustomSaveHelper::fileToStack(const Common::String &filename, StackHandler *sH) {
Variable stringVar;
stringVar.varType = SVT_NULL;
Common::String checker = _saveEncoding ? "[Custom data (encoded)]\r\n" : "[Custom data (ASCII)]\n";
Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(filename);
if (fp == NULL) {
return fatal("No such file", filename); //TODO: false value
}
_encode1 = (byte)_saveEncoding & 255;
_encode2 = (byte)(_saveEncoding >> 8);
for (uint i = 0; i < checker.size(); ++i) {
if (fp->readByte() != checker[i]) {
delete fp;
return fatal(LOAD_ERROR "This isn't a SLUDGE custom data file:", filename);
}
}
if (_saveEncoding) {
checker = readStringEncoded(fp);
if (checker == UTF8_CHECKER) {
delete fp;
return fatal(LOAD_ERROR "The current file encoding setting does not match the encoding setting used when this file was created:", filename);
}
}
for (;;) {
if (_saveEncoding) {
char i = fp->readByte() ^ _encode1;
if (fp->eos())
break;
switch (i) {
case 0: {
Common::String g = readStringEncoded(fp);
makeTextVar(stringVar, g);
}
break;
case 1:
setVariable(stringVar, SVT_INT, fp->readUint32LE());
break;
case 2:
setVariable(stringVar, SVT_INT, fp->readByte());
break;
default:
fatal(LOAD_ERROR "Corrupt custom data file:", filename);
delete fp;
return false;
}
} else {
char *line = readTextPlain(fp);
if (!line)
break;
makeTextVar(stringVar, line);
}
if (sH->first == NULL) {
// Adds to the TOP of the array... oops!
if (!addVarToStackQuick(stringVar, sH->first))
return false;
sH->last = sH->first;
} else {
// Adds to the END of the array... much better
if (!addVarToStackQuick(stringVar, sH->last->next))
return false;
sH->last = sH->last->next;
}
}
delete fp;
return true;
}
bool CustomSaveHelper::stackToFile(const Common::String &filename, const Variable &from) {
Common::OutSaveFile *fp = g_system->getSavefileManager()->openForSaving(filename);
if (fp == NULL) {
return fatal("Can't create file", filename);
}
VariableStack *hereWeAre = from.varData.theStack -> first;
_encode1 = (byte)_saveEncoding & 255;
_encode2 = (byte)(_saveEncoding >> 8);
if (_saveEncoding) {
fp->writeString("[Custom data (encoded)]\r\n");
writeStringEncoded(UTF8_CHECKER, fp);
} else {
fp->writeString("[Custom data (ASCII)]\n");
}
while (hereWeAre) {
if (_saveEncoding) {
switch (hereWeAre -> thisVar.varType) {
case SVT_STRING:
fp->writeByte(_encode1);
writeStringEncoded(hereWeAre -> thisVar.varData.theString, fp);
break;
case SVT_INT:
// Small enough to be stored as a char
if (hereWeAre -> thisVar.varData.intValue >= 0 && hereWeAre -> thisVar.varData.intValue < 256) {
fp->writeByte(2 ^ _encode1);
fp->writeByte(hereWeAre -> thisVar.varData.intValue);
} else {
fp->writeByte(1 ^ _encode1);
fp->writeUint32LE(hereWeAre -> thisVar.varData.intValue);
}
break;
default:
fatal("Can't create an encoded custom data file containing anything other than numbers and strings", filename);
delete fp;
return false;
}
} else {
Common::String makeSureItsText = getTextFromAnyVar(hereWeAre -> thisVar);
if (makeSureItsText.empty())
break;
fp->writeString((makeSureItsText + "\n").c_str());
}
hereWeAre = hereWeAre -> next;
}
delete fp;
return true;
}
} // End of namespace Sludge