aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/streams.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/glk/streams.cpp')
-rw-r--r--engines/glk/streams.cpp1592
1 files changed, 1592 insertions, 0 deletions
diff --git a/engines/glk/streams.cpp b/engines/glk/streams.cpp
new file mode 100644
index 0000000000..d53f5d72a1
--- /dev/null
+++ b/engines/glk/streams.cpp
@@ -0,0 +1,1592 @@
+/* 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 "glk/streams.h"
+#include "glk/conf.h"
+#include "glk/events.h"
+#include "glk/gargoyle.h"
+#include "glk/windows.h"
+#include "gui/saveload.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/translation.h"
+
+namespace Gargoyle {
+
+Stream::Stream(Streams *streams, bool readable, bool writable, uint32 rock, bool unicode) :
+ _streams(streams), _readable(readable), _writable(writable), _readCount(0),
+ _writeCount(0), _prev(nullptr), _next(nullptr), _rock(0) {
+}
+
+Stream::~Stream() {
+ _streams->removeStream(this);
+}
+
+Stream *Stream::getNext(uint32 *rock) const {
+ Stream *stream = _next;
+ if (rock)
+ *rock = stream ? stream->_rock : 0;
+ return stream;
+}
+
+void Stream::fillResult(StreamResult *result) {
+ if (result) {
+ result->_readCount = _readCount;
+ result->_writeCount = _writeCount;
+ }
+}
+
+void Stream::close(StreamResult *result) {
+ // Get the read/write totals
+ fillResult(result);
+
+ // Remove the stream
+ delete this;
+}
+
+void Stream::setZColors(glui32 fg, glui32 bg) {
+ if (_writable && g_conf->_styleHint)
+ Windows::_forceRedraw = true;
+}
+
+void Stream::setReverseVideo(bool reverse) {
+ if (_writable && g_conf->_styleHint)
+ Windows::_forceRedraw = true;
+}
+
+/*--------------------------------------------------------------------------*/
+
+void WindowStream::close(StreamResult *result) {
+ warning("cannot close window stream");
+}
+
+void WindowStream::putChar(unsigned char ch) {
+ if (!_writable)
+ return;
+ ++_writeCount;
+
+ if (_window->_lineRequest || _window->_lineRequestUni) {
+ if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
+ _window->cancelLineEvent(nullptr);
+ g_vm->_events->_forceClick = false;
+ } else {
+ warning("putChar: window has pending line request");
+ }
+ }
+
+ _window->putCharUni(ch);
+ if (_window->_echoStream)
+ _window->_echoStream->putChar(ch);
+}
+
+void WindowStream::putCharUni(uint32 ch) {
+ if (!_writable)
+ return;
+ ++_writeCount;
+
+ if (_window->_lineRequest || _window->_lineRequestUni) {
+ if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
+ _window->cancelLineEvent(nullptr);
+ g_vm->_events->_forceClick = false;
+ } else {
+ warning("putCharUni: window has pending line request");
+ }
+ }
+
+ _window->putCharUni(ch);
+ if (_window->_echoStream)
+ _window->_echoStream->putCharUni(ch);
+}
+
+void WindowStream::putBuffer(const char *buf, size_t len) {
+ if (!_writable)
+ return;
+ _writeCount += len;
+
+ if (_window->_lineRequest || _window->_lineRequestUni) {
+ if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
+ _window->cancelLineEvent(nullptr);
+ g_vm->_events->_forceClick = false;
+ } else {
+ warning("putBuffer: window has pending line request");
+ }
+ }
+
+ for (size_t lx = 0; lx < len; lx++, buf++)
+ _window->putCharUni(*buf);
+ if (_window->_echoStream)
+ _window->_echoStream->putBuffer(buf, len);
+}
+
+void WindowStream::putBufferUni(const uint32 *buf, size_t len) {
+ if (!_writable)
+ return;
+ _writeCount += len;
+
+ if (_window->_lineRequest || _window->_lineRequestUni) {
+ if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
+ _window->cancelLineEvent(nullptr);
+ g_vm->_events->_forceClick = false;
+ } else {
+ warning("putBuffer: window has pending line request");
+ }
+ }
+
+ for (size_t lx = 0; lx < len; lx++, buf++)
+ _window->putCharUni(*buf);
+ if (_window->_echoStream)
+ _window->_echoStream->putBufferUni(buf, len);
+}
+
+void WindowStream::unputBuffer(const char *buf, size_t len) {
+ glui32 lx;
+ const char *cx;
+
+ if (!_writable)
+ return;
+
+ if (_window->_lineRequest || _window->_lineRequestUni) {
+ if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
+ _window->cancelLineEvent(nullptr);
+ g_vm->_events->_forceClick = false;
+ } else {
+ warning("unput_buffer: window has pending line request");
+ return;
+ }
+ }
+
+ for (lx = 0, cx = buf + len - 1; lx < len; lx++, cx--) {
+ if (!_window->unputCharUni(*cx))
+ break;
+ _writeCount--;
+ }
+ if (_window->_echoStream)
+ _window->_echoStream->unputBuffer(buf, len);
+}
+
+void WindowStream::unputBufferUni(const glui32 *buf, size_t len) {
+ glui32 lx;
+ const glui32 *cx;
+
+ if (!_writable)
+ return;
+
+ if (_window->_lineRequest || _window->_lineRequestUni) {
+ if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
+ _window->cancelLineEvent(nullptr);
+ g_vm->_events->_forceClick = false;
+ } else {
+ warning("unput_buffer: window has pending line request");
+ return;
+ }
+ }
+
+ for (lx = 0, cx = buf + len - 1; lx < len; lx++, cx--) {
+ if (!_window->unputCharUni(*cx))
+ break;
+ _writeCount--;
+ }
+
+ if (_window->_echoStream)
+ _window->_echoStream->unputBufferUni(buf, len);
+}
+
+void WindowStream::setStyle(glui32 val) {
+ if (!_writable)
+ return;
+
+ if (val >= style_NUMSTYLES)
+ val = 0;
+
+ _window->_attr.style = val;
+ if (_window->_echoStream)
+ _window->_echoStream->setStyle(val);
+}
+
+void WindowStream::setHyperlink(glui32 linkVal) {
+ if (_writable)
+ _window->_attr.hyper = linkVal;
+}
+
+void WindowStream::setZColors(glui32 fg, glui32 bg) {
+ if (!_writable || !g_conf->_styleHint)
+ return;
+
+ byte fore[3], back[3];
+ fore[0] = (fg >> 16) & 0xff;
+ fore[1] = (fg >> 8) & 0xff;
+ fore[2] = (fg) & 0xff;
+ back[0] = (bg >> 16) & 0xff;
+ back[1] = (bg >> 8) & 0xff;
+ back[2] = (bg) & 0xff;
+
+ if (fg != zcolor_Transparent && fg != zcolor_Cursor) {
+ if (fg == zcolor_Default) {
+ _window->_attr.fgset = 0;
+ _window->_attr.fgcolor = 0;
+ Windows::_overrideFgSet = false;
+ Windows::_overrideFgVal = 0;
+
+ Common::copy(g_conf->_moreSave, g_conf->_moreSave + 3, g_conf->_moreColor);
+ Common::copy(g_conf->_caretSave, g_conf->_caretSave + 3, g_conf->_caretColor);
+ Common::copy(g_conf->_linkSave, g_conf->_linkSave + 3, g_conf->_linkColor);
+ } else if (fg != zcolor_Current) {
+ _window->_attr.fgset = 1;
+ _window->_attr.fgcolor = fg;
+ Windows::_overrideFgSet = true;
+ Windows::_overrideFgVal = fg;
+
+ Common::copy(fore, fore + 3, g_conf->_moreColor);
+ Common::copy(fore, fore + 3, g_conf->_caretColor);
+ Common::copy(fore, fore + 3, g_conf->_linkColor);
+ }
+ }
+
+ if (bg != zcolor_Transparent && bg != zcolor_Cursor) {
+ if (bg == zcolor_Default) {
+ _window->_attr.bgset = 0;
+ _window->_attr.bgcolor = 0;
+ Windows::_overrideBgSet = false;
+ Windows::_overrideBgVal = 0;
+
+ Common::copy(g_conf->_windowSave, g_conf->_windowSave + 3, g_conf->_windowColor);
+ Common::copy(g_conf->_borderSave, g_conf->_borderSave + 3, g_conf->_borderColor);
+ } else if (bg != zcolor_Current) {
+ _window->_attr.bgset = 1;
+ _window->_attr.bgcolor = bg;
+ Windows::_overrideBgSet = true;
+ Windows::_overrideBgVal = bg;
+
+ Common::copy(back, back + 3, g_conf->_windowColor);
+ Common::copy(back, back + 3, g_conf->_borderColor);
+ }
+ }
+
+ Windows::_overrideReverse = !(fg == zcolor_Default && bg == zcolor_Default);
+ Windows::_forceRedraw = true;
+
+ if (_window->_echoStream)
+ _window->_echoStream->setZColors(fg, bg);
+}
+
+void WindowStream::setReverseVideo(bool reverse) {
+ if (!_writable || !g_conf->_styleHint)
+ return;
+
+ _window->_attr.reverse = reverse;
+ if (_window->_echoStream)
+ _window->_echoStream->setReverseVideo(reverse);
+
+ Windows::_forceRedraw = true;
+}
+
+/*--------------------------------------------------------------------------*/
+
+MemoryStream::MemoryStream(Streams *streams, void *buf, size_t buflen, FileMode mode, uint32 rock, bool unicode) :
+ Stream(streams, mode != filemode_Write, mode != filemode_Read, rock, unicode),
+ _buf(buf), _bufLen(buflen), _bufPtr(buf) {
+ assert(_buf && _bufLen);
+ assert(mode == filemode_Read || mode == filemode_Write || mode == filemode_ReadWrite);
+
+ if (unicode)
+ _bufEnd = (uint32 *)buf + buflen;
+ else
+ _bufEnd = (byte *)buf + buflen;
+ _bufEof = mode == filemode_Write ? _buf : _bufEnd;
+}
+
+void MemoryStream::putChar(unsigned char ch) {
+ if (!_writable)
+ return;
+ ++_writeCount;
+
+ if (_bufPtr < _bufEnd) {
+ if (_unicode) {
+ *((glui32 *)_bufPtr) = ch;
+ _bufPtr = ((glui32 *)_bufPtr) + 1;
+ } else {
+ *((unsigned char *)_bufPtr) = ch;
+ _bufPtr = ((unsigned char *)_bufPtr) + 1;
+ }
+
+ if (_bufPtr > _bufEof)
+ _bufEof = _bufPtr;
+ }
+}
+
+void MemoryStream::putCharUni(uint32 ch) {
+ if (!_writable)
+ return;
+ ++_writeCount;
+
+ if (_bufPtr < _bufEnd) {
+ if (_unicode) {
+ *((glui32 *)_bufPtr) = ch;
+ _bufPtr = ((glui32 *)_bufPtr) + 1;
+ } else {
+ *((unsigned char *)_bufPtr) = (unsigned char)ch;
+ _bufPtr = ((unsigned char *)_bufPtr) + 1;
+ }
+ if (_bufPtr > _bufEof)
+ _bufEof = _bufPtr;
+ }
+}
+
+void MemoryStream::putBuffer(const char *buf, size_t len) {
+ size_t lx;
+
+ if (!_writable)
+ return;
+ _writeCount += len;
+
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if (!_unicode) {
+ unsigned char *bp = (unsigned char *)_bufPtr;
+ if (bp + len > (unsigned char *)_bufEnd) {
+ lx = (bp + len) - (unsigned char *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ if (len) {
+ memmove(bp, buf, len);
+ bp += len;
+ if (bp > (unsigned char *)_bufEof)
+ _bufEof = bp;
+ }
+ _bufPtr = bp;
+ } else {
+ glui32 *bp = (glui32 *)_bufPtr;
+ if (bp + len > (glui32 *)_bufEnd) {
+ lx = (bp + len) - (glui32 *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ if (len) {
+ glui32 i;
+ for (i = 0; i < len; i++)
+ bp[i] = buf[i];
+ bp += len;
+ if (bp > (glui32 *)_bufEof)
+ _bufEof = bp;
+ }
+ _bufPtr = bp;
+ }
+ }
+}
+
+void MemoryStream::putBufferUni(const uint32 *buf, size_t len) {
+ size_t lx;
+
+ if (!_writable)
+ return;
+ _writeCount += len;
+
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if (!_unicode) {
+ unsigned char *bp = (unsigned char *)_bufPtr;
+ if (bp + len > (unsigned char *)_bufEnd) {
+ lx = (bp + len) - (unsigned char *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ if (len) {
+ glui32 i;
+ for (i = 0; i < len; i++) {
+ glui32 ch = buf[i];
+ if (ch > 0xff)
+ ch = '?';
+ bp[i] = (unsigned char)ch;
+ }
+ bp += len;
+ if (bp > (unsigned char *)_bufEof)
+ _bufEof = bp;
+ }
+ _bufPtr = bp;
+ } else {
+ glui32 *bp = (glui32 *)_bufPtr;
+ if (bp + len > (glui32 *)_bufEnd) {
+ lx = (bp + len) - (glui32 *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ if (len) {
+ memmove(bp, buf, len * 4);
+ bp += len;
+ if (bp > (glui32 *)_bufEof)
+ _bufEof = bp;
+ }
+ _bufPtr = bp;
+ }
+ }
+}
+
+glui32 MemoryStream::getPosition() const {
+ if (_unicode)
+ return ((glui32 *)_bufPtr - (glui32 *)_buf);
+ else
+ return ((unsigned char *)_bufPtr - (unsigned char *)_buf);
+}
+
+void MemoryStream::setPosition(glsi32 pos, glui32 seekMode) {
+ if (!_unicode) {
+ if (seekMode == seekmode_Current)
+ pos = ((unsigned char *)_bufPtr - (unsigned char *)_buf) + pos;
+ else if (seekMode == seekmode_End)
+ pos = ((unsigned char *)_bufEof - (unsigned char *)_buf) + pos;
+ else
+ /* pos = pos */;
+ if (pos < 0)
+ pos = 0;
+ if (pos > ((unsigned char *)_bufEof - (unsigned char *)_buf))
+ pos = ((unsigned char *)_bufEof - (unsigned char *)_buf);
+ _bufPtr = (unsigned char *)_buf + pos;
+ } else {
+ if (seekMode == seekmode_Current)
+ pos = ((glui32 *)_bufPtr - (glui32 *)_buf) + pos;
+ else if (seekMode == seekmode_End)
+ pos = ((glui32 *)_bufEof - (glui32 *)_buf) + pos;
+
+ if (pos < 0)
+ pos = 0;
+ if (pos > ((glui32 *)_bufEof - (glui32 *)_buf))
+ pos = ((glui32 *)_bufEof - (glui32 *)_buf);
+ _bufPtr = (glui32 *)_buf + pos;
+ }
+}
+
+glsi32 MemoryStream::getChar() {
+ if (!_readable)
+ return -1;
+
+ if (_bufPtr < _bufEnd) {
+ if (!_unicode) {
+ unsigned char ch;
+ ch = *((unsigned char *)_bufPtr);
+ _bufPtr = ((unsigned char *)_bufPtr) + 1;
+ _readCount++;
+ return ch;
+ } else {
+ glui32 ch;
+ ch = *((glui32 *)_bufPtr);
+ _bufPtr = ((glui32 *)_bufPtr) + 1;
+ _readCount++;
+ if (ch > 0xff)
+ ch = '?';
+ return ch;
+ }
+ } else {
+ return -1;
+ }
+}
+
+glsi32 MemoryStream::getCharUni() {
+ if (!_readable)
+ return -1;
+
+ if (_bufPtr < _bufEnd) {
+ if (!_unicode) {
+ unsigned char ch;
+ ch = *((unsigned char *)_bufPtr);
+ _bufPtr = ((unsigned char *)_bufPtr) + 1;
+ _readCount++;
+ return ch;
+ } else {
+ glui32 ch;
+ ch = *((glui32 *)_bufPtr);
+ _bufPtr = ((glui32 *)_bufPtr) + 1;
+ _readCount++;
+ return ch;
+ }
+ } else {
+ return -1;
+ }
+}
+
+glui32 MemoryStream::getBuffer(char *buf, glui32 len) {
+ if (!_readable)
+ return 0;
+
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if (!_unicode) {
+ unsigned char *bp = (unsigned char *)_bufPtr;
+ if (bp + len > (unsigned char *)_bufEnd) {
+ glui32 lx;
+ lx = (bp + len) - (unsigned char *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+
+ if (len) {
+ memcpy(buf, bp, len);
+ bp += len;
+ if (bp > (unsigned char *)_bufEof)
+ _bufEof = bp;
+ }
+
+ _readCount += len;
+ _bufPtr = bp;
+ } else {
+ glui32 *bp = (glui32 *)_bufPtr;
+ if (bp + len > (glui32 *)_bufEnd) {
+ glui32 lx;
+ lx = (bp + len) - (glui32 *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ if (len) {
+ glui32 i;
+ for (i = 0; i < len; i++) {
+ glui32 ch = *bp++;
+ if (ch > 0xff)
+ ch = '?';
+ *buf++ = (char)ch;
+ }
+ if (bp > (glui32 *)_bufEof)
+ _bufEof = bp;
+ }
+
+ _readCount += len;
+ _bufPtr = bp;
+ }
+ }
+
+ return len;
+}
+
+glui32 MemoryStream::getBufferUni(glui32 *buf, glui32 len) {
+ if (!_readable)
+ return 0;
+
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if (!_unicode) {
+ unsigned char *bp = (unsigned char *)_bufPtr;
+ if (bp + len > (unsigned char *)_bufEnd) {
+ glui32 lx;
+ lx = (bp + len) - (unsigned char *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ if (len) {
+ glui32 i;
+ for (i = 0; i < len; i++)
+ buf[i] = bp[i];
+ bp += len;
+ if (bp > (unsigned char *)_bufEof)
+ _bufEof = bp;
+ }
+ _readCount += len;
+ _bufPtr = bp;
+ } else {
+ glui32 *bp = (glui32 *)_bufPtr;
+ if (bp + len > (glui32 *)_bufEnd) {
+ glui32 lx;
+ lx = (bp + len) - (glui32 *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ if (len) {
+ memcpy(buf, bp, len * 4);
+ bp += len;
+ if (bp > (glui32 *)_bufEof)
+ _bufEof = bp;
+ }
+ _readCount += len;
+ _bufPtr = bp;
+ }
+ }
+
+ return len;
+}
+
+glui32 MemoryStream::getLine(char *buf, glui32 len) {
+ glui32 lx;
+ bool gotNewline;
+
+ if (len == 0)
+ return 0;
+
+ len -= 1; /* for the terminal null */
+ if (!_unicode) {
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if ((char *)_bufPtr + len > (char *)_bufEnd) {
+ lx = ((char *)_bufPtr + len) - (char *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ }
+
+ gotNewline = false;
+ for (lx = 0; lx < len && !gotNewline; lx++) {
+ buf[lx] = ((char *)_bufPtr)[lx];
+ gotNewline = (buf[lx] == '\n');
+ }
+
+ buf[lx] = '\0';
+ _bufPtr = ((char *)_bufPtr) + lx;
+ } else {
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if ((char *)_bufPtr + len > (char *)_bufEnd) {
+ lx = ((char *)_bufPtr + len) - (char *)_bufEnd;
+ if (lx < len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ }
+
+ gotNewline = false;
+ for (lx = 0; lx < len && !gotNewline; lx++) {
+ glui32 ch;
+ ch = ((glui32 *)_bufPtr)[lx];
+ if (ch >= 0x100)
+ ch = '?';
+ buf[lx] = (char)ch;
+ gotNewline = (ch == '\n');
+ }
+
+ buf[lx] = '\0';
+ _bufPtr = ((glui32 *)_bufPtr) + lx;
+ }
+
+ _readCount += lx;
+ return lx;
+}
+
+glui32 MemoryStream::getLineUni(glui32 *ubuf, glui32 len) {
+ bool gotNewline;
+ int lx;
+
+ if (!_readable || len == 0)
+ return 0;
+
+ len -= 1; // for the terminal null
+ if (!_unicode) {
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if ((char *)_bufPtr + len > (char *)_bufEnd) {
+ lx = ((char *)_bufPtr + len) - (char *)_bufEnd;
+ if (lx < (int)len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ }
+ gotNewline = false;
+ for (lx = 0; lx < (int)len && !gotNewline; lx++) {
+ ubuf[lx] = ((unsigned char *)_bufPtr)[lx];
+ gotNewline = (ubuf[lx] == '\n');
+ }
+ ubuf[lx] = '\0';
+ _bufPtr = ((unsigned char *)_bufPtr) + lx;
+ } else {
+ if (_bufPtr >= _bufEnd) {
+ len = 0;
+ } else {
+ if ((glui32 *)_bufPtr + len > (glui32 *)_bufEnd) {
+ lx = ((glui32 *)_bufPtr + len) - (glui32 *)_bufEnd;
+ if (lx < (int)len)
+ len -= lx;
+ else
+ len = 0;
+ }
+ }
+ gotNewline = false;
+ for (lx = 0; lx < (int)len && !gotNewline; lx++) {
+ glui32 ch;
+ ch = ((glui32 *)_bufPtr)[lx];
+ ubuf[lx] = ch;
+ gotNewline = (ch == '\n');
+ }
+ ubuf[lx] = '\0';
+ _bufPtr = ((glui32 *)_bufPtr) + lx;
+ }
+
+ _readCount += lx;
+ return lx;
+}
+
+/*--------------------------------------------------------------------------*/
+
+FileStream::FileStream(Streams *streams, frefid_t fref, glui32 fmode, glui32 rock, bool unicode) :
+ Stream(streams, fmode == filemode_Read, fmode != filemode_Read, rock, unicode), _lastOp(0),
+ _textFile(fref->_textMode), _inFile(nullptr), _outFile(nullptr), _inStream(nullptr) {
+ Common::String fname = fref->_slotNumber == -1 ? fref->_filename : fref->getSaveName();
+
+ if (fmode == filemode_Write || fmode == filemode_ReadWrite || fmode == filemode_WriteAppend) {
+ _outFile = g_system->getSavefileManager()->openForSaving(fname, fref->_slotNumber != -1);
+ if (!_outFile)
+ error("Could open file for writing - %s", fname.c_str());
+
+ if (fref->_slotNumber != -1)
+ writeSavegameHeader(_outFile, fref->_description);
+ } else if (fmode == filemode_Read) {
+ if (_file.open(fname)) {
+ _inStream = &_file;
+ } else {
+ _inFile = g_system->getSavefileManager()->openForLoading(fname);
+ _inStream = _inFile;
+ }
+
+ if (!_inStream)
+ error("Could not open for reading - %s", fname.c_str());
+
+ if (_inFile) {
+ // It's a save file, so skip over the header
+ SavegameHeader header;
+ if (!readSavegameHeader(_inStream, header))
+ error("Invalid savegame");
+ if (header._interpType != g_vm->getInterpreterType() || header._language != g_vm->getLanguage()
+ || header._md5 != g_vm->getGameMD5())
+ error("Savegame is for a different game");
+
+ g_vm->_events->setTotalPlayTicks(header._totalFrames);
+ }
+ }
+}
+
+FileStream::~FileStream() {
+ _file.close();
+ delete _inFile;
+ if (_outFile) {
+ _outFile->finalize();
+ delete _outFile;
+ }
+}
+
+void FileStream::ensureOp(FileMode mode) {
+ // No implementation
+}
+
+void FileStream::putChar(unsigned char ch) {
+ if (!_writable)
+ return;
+ ++_writeCount;
+
+ ensureOp(filemode_Write);
+ if (!_unicode) {
+ _outFile->writeByte(ch);
+ } else if (_textFile) {
+ putCharUtf8((glui32)ch);
+ } else {
+ _outFile->writeUint32BE(ch);
+ }
+
+ _outFile->flush();
+}
+
+void FileStream::putCharUni(uint32 ch) {
+ if (!_writable)
+ return;
+ ++_writeCount;
+
+ ensureOp(filemode_Write);
+ if (!_unicode) {
+ if (ch >= 0x100)
+ ch = '?';
+ _outFile->writeByte(ch);
+ } else if (_textFile) {
+ putCharUtf8(ch);
+ } else {
+ _outFile->writeUint32BE(ch);
+ }
+
+ _outFile->flush();
+}
+
+void FileStream::putBuffer(const char *buf, size_t len) {
+ if (!_writable)
+ return;
+ _writeCount += len;
+
+ ensureOp(filemode_Write);
+ for (size_t lx = 0; lx < len; lx++) {
+ unsigned char ch = ((const unsigned char *)buf)[lx];
+ if (!_unicode) {
+ _outFile->writeByte(ch);
+ } else if (_textFile) {
+ putCharUtf8((glui32)ch);
+ } else {
+ _outFile->writeUint32BE(ch);
+ }
+ }
+
+ _outFile->flush();
+}
+
+void FileStream::putBufferUni(const uint32 *buf, size_t len) {
+ if (!_writable)
+ return;
+ _writeCount += len;
+
+
+ ensureOp(filemode_Write);
+ for (size_t lx = 0; lx < len; lx++) {
+ glui32 ch = buf[lx];
+ if (!_unicode) {
+ if (ch >= 0x100)
+ ch = '?';
+ _outFile->writeByte(ch);
+ } else if (_textFile) {
+ putCharUtf8(ch);
+ } else {
+ _outFile->writeUint32BE(ch);
+ }
+ }
+
+ _outFile->flush();
+}
+
+void FileStream::putCharUtf8(glui32 val) {
+ if (val < 0x80) {
+ _outFile->writeByte(val);
+ } else if (val < 0x800) {
+ _outFile->writeByte((0xC0 | ((val & 0x7C0) >> 6)));
+ _outFile->writeByte((0x80 | (val & 0x03F)));
+ } else if (val < 0x10000) {
+ _outFile->writeByte((0xE0 | ((val & 0xF000) >> 12)));
+ _outFile->writeByte((0x80 | ((val & 0x0FC0) >> 6)));
+ _outFile->writeByte((0x80 | (val & 0x003F)));
+ } else if (val < 0x200000) {
+ _outFile->writeByte((0xF0 | ((val & 0x1C0000) >> 18)));
+ _outFile->writeByte((0x80 | ((val & 0x03F000) >> 12)));
+ _outFile->writeByte((0x80 | ((val & 0x000FC0) >> 6)));
+ _outFile->writeByte((0x80 | (val & 0x00003F)));
+ } else {
+ _outFile->writeByte('?');
+ }
+}
+
+glsi32 FileStream::getCharUtf8() {
+ glui32 res;
+ glui32 val0, val1, val2, val3;
+
+ if (_inStream->eos())
+ return -1;
+ val0 = _inStream->readByte();
+ if (val0 < 0x80) {
+ res = val0;
+ return res;
+ }
+
+ if ((val0 & 0xe0) == 0xc0) {
+ if (_inStream->eos()) {
+ warning("incomplete two-byte character");
+ return -1;
+ }
+
+ val1 = _inStream->readByte();
+ if ((val1 & 0xc0) != 0x80) {
+ warning("malformed two-byte character");
+ return '?';
+ }
+
+ res = (val0 & 0x1f) << 6;
+ res |= (val1 & 0x3f);
+ return res;
+ }
+
+ if ((val0 & 0xf0) == 0xe0) {
+ val1 = _inStream->readByte();
+ val2 = _inStream->readByte();
+ if (_inStream->eos()) {
+ warning("incomplete three-byte character");
+ return -1;
+ }
+ if ((val1 & 0xc0) != 0x80) {
+ warning("malformed three-byte character");
+ return '?';
+ }
+ if ((val2 & 0xc0) != 0x80) {
+ warning("malformed three-byte character");
+ return '?';
+ }
+
+ res = (((val0 & 0xf) << 12) & 0x0000f000);
+ res |= (((val1 & 0x3f) << 6) & 0x00000fc0);
+ res |= (((val2 & 0x3f)) & 0x0000003f);
+ return res;
+ }
+
+ if ((val0 & 0xf0) == 0xf0) {
+ if ((val0 & 0xf8) != 0xf0) {
+ warning("malformed four-byte character");
+ return '?';
+ }
+
+ val1 = _inStream->readByte();
+ val2 = _inStream->readByte();
+ val3 = _inStream->readByte();
+ if (_inStream->eos()) {
+ warning("incomplete four-byte character");
+ return -1;
+ }
+ if ((val1 & 0xc0) != 0x80) {
+ warning("malformed four-byte character");
+ return '?';
+ }
+ if ((val2 & 0xc0) != 0x80) {
+ warning("malformed four-byte character");
+ return '?';
+ }
+ if ((val3 & 0xc0) != 0x80) {
+ warning("malformed four-byte character");
+ return '?';
+ }
+
+ res = (((val0 & 0x7) << 18) & 0x1c0000);
+ res |= (((val1 & 0x3f) << 12) & 0x03f000);
+ res |= (((val2 & 0x3f) << 6) & 0x000fc0);
+ res |= (((val3 & 0x3f)) & 0x00003f);
+ return res;
+ }
+
+ warning("malformed character");
+ return '?';
+}
+
+glui32 FileStream::getPosition() const {
+ return _outFile ? _outFile->pos() : _inStream->pos();
+}
+
+void FileStream::setPosition(glsi32 pos, glui32 seekMode) {
+ _lastOp = 0;
+ if (_unicode)
+ pos *= 4;
+
+ if (_inStream) {
+ _inStream->seek(pos, SEEK_SET);
+ } else {
+ error("seek not supported for writing files");
+ }
+}
+
+glsi32 FileStream::getChar() {
+ if (!_readable)
+ return -1;
+
+ ensureOp(filemode_Read);
+ int res;
+ if (!_unicode) {
+ res = _inStream->readByte();
+ } else if (_textFile) {
+ res = getCharUtf8();
+ } else {
+ glui32 ch;
+ res = _inStream->readByte();
+ if (_inStream->eos())
+ return -1;
+ ch = (res & 0xFF);
+ res = _inStream->readByte();
+ if (_inStream->eos())
+ return -1;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (_inStream->eos())
+ return -1;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (_inStream->eos())
+ return -1;
+ ch = (ch << 8) | (res & 0xFF);
+ res = ch;
+ }
+ if (res != -1) {
+ _readCount++;
+ if (res >= 0x100)
+ return '?';
+ return (glsi32)res;
+ } else {
+ return -1;
+ }
+}
+
+glsi32 FileStream::getCharUni() {
+ if (!_readable)
+ return -1;
+
+ ensureOp(filemode_Read);
+ int res;
+ if (!_unicode) {
+ res = _inStream->readByte();
+ } else if (_textFile) {
+ res = getCharUtf8();
+ } else {
+ glui32 ch;
+ res = _inStream->readByte();
+ if (res == -1)
+ return -1;
+ ch = (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ return -1;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ return -1;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ return -1;
+ ch = (ch << 8) | (res & 0xFF);
+ res = ch;
+ }
+ if (res != -1) {
+ _readCount++;
+ return (glsi32)res;
+ } else {
+ return -1;
+ }
+}
+
+glui32 FileStream::getBuffer(char *buf, glui32 len) {
+ ensureOp(filemode_Read);
+ if (!_unicode) {
+ glui32 res;
+ res = _inStream->read(buf, len);
+ _readCount += res;
+ return res;
+ } else if (_textFile) {
+ glui32 lx;
+ for (lx = 0; lx < len; lx++) {
+ glui32 ch;
+ ch = getCharUtf8();
+ if (ch == (glui32)-1)
+ break;
+ _readCount++;
+ if (ch >= 0x100)
+ ch = '?';
+ buf[lx] = (char)ch;
+ }
+ return lx;
+ } else {
+ glui32 lx;
+ for (lx = 0; lx < len; lx++) {
+ int res;
+ glui32 ch;
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ _readCount++;
+ if (ch >= 0x100)
+ ch = '?';
+ buf[lx] = (char)ch;
+ }
+ return lx;
+ }
+}
+
+glui32 FileStream::getBufferUni(glui32 *buf, glui32 len) {
+ if (!_readable)
+ return 0;
+
+ ensureOp(filemode_Read);
+ if (!_unicode) {
+ glui32 lx;
+ for (lx = 0; lx < len; lx++) {
+ int res;
+ glui32 ch;
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (res & 0xFF);
+ _readCount++;
+ buf[lx] = ch;
+ }
+ return lx;
+ } else if (_textFile) {
+ glui32 lx;
+ for (lx = 0; lx < len; lx++) {
+ glui32 ch;
+ ch = getCharUtf8();
+ if (ch == (glui32)-1)
+ break;
+ _readCount++;
+ buf[lx] = ch;
+ }
+ return lx;
+ } else {
+ glui32 lx;
+ for (lx = 0; lx < len; lx++) {
+ int res;
+ glui32 ch;
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ _readCount++;
+ buf[lx] = ch;
+ }
+ return lx;
+ }
+}
+
+glui32 FileStream::getLine(char *buf, glui32 len) {
+ glui32 lx;
+ bool gotNewline;
+
+ if (len == 0)
+ return 0;
+
+ ensureOp(filemode_Read);
+ if (!_unicode) {
+ char *res = buf;
+ for (; len > 0; ++res, --len) {
+ *res = _inStream->readByte();
+ if (*res == '\n')
+ break;
+ }
+ *res = '\0';
+
+ lx = strlen(buf);
+ _readCount += lx;
+ return lx;
+ } else if (_textFile) {
+ len -= 1; // for the terminal null
+ gotNewline = false;
+ for (lx = 0; lx < len && !gotNewline; lx++) {
+ glui32 ch;
+ ch = getCharUtf8();
+ if (ch == (glui32)-1)
+ break;
+ _readCount++;
+ if (ch >= 0x100)
+ ch = '?';
+ buf[lx] = (char)ch;
+ gotNewline = (ch == '\n');
+ }
+ buf[lx] = '\0';
+ return lx;
+ } else {
+ len -= 1; // for the terminal null
+ gotNewline = false;
+ for (lx = 0; lx < len && !gotNewline; lx++) {
+ int res;
+ glui32 ch;
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ _readCount++;
+ if (ch >= 0x100)
+ ch = '?';
+ buf[lx] = (char)ch;
+ gotNewline = (ch == '\n');
+ }
+
+ buf[lx] = '\0';
+ return lx;
+ }
+}
+
+glui32 FileStream::getLineUni(glui32 *ubuf, glui32 len) {
+ bool gotNewline;
+ int lx;
+
+ if (!_readable || len == 0)
+ return 0;
+
+ ensureOp(filemode_Read);
+ if (!_unicode) {
+ len -= 1; // for the terminal null
+ gotNewline = false;
+ for (lx = 0; lx < (int)len && !gotNewline; lx++) {
+ int res;
+ glui32 ch;
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (res & 0xFF);
+ _readCount++;
+ ubuf[lx] = ch;
+ gotNewline = (ch == '\n');
+ }
+ ubuf[lx] = '\0';
+ return lx;
+ } else if (_textFile) {
+ len -= 1; /* for the terminal null */
+ gotNewline = false;
+ for (lx = 0; lx < (int)len && !gotNewline; lx++) {
+ glui32 ch;
+ ch = getCharUtf8();
+ if (ch == (glui32)-1)
+ break;
+ _readCount++;
+ ubuf[lx] = ch;
+ gotNewline = (ch == '\n');
+ }
+ ubuf[lx] = '\0';
+ return lx;
+ } else {
+ len -= 1; // for the terminal null
+ gotNewline = false;
+ for (lx = 0; lx < (int)len && !gotNewline; lx++) {
+ int res;
+ glui32 ch;
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ res = _inStream->readByte();
+ if (res == -1)
+ break;
+ ch = (ch << 8) | (res & 0xFF);
+ _readCount++;
+ ubuf[lx] = ch;
+ gotNewline = (ch == '\n');
+ }
+ ubuf[lx] = '\0';
+ return lx;
+ }
+}
+
+static Common::String readString(Common::ReadStream *src) {
+ char c;
+ Common::String result;
+ while ((c = src->readByte()) != 0)
+ result += c;
+
+ return result;
+}
+
+bool FileStream::readSavegameHeader(Common::SeekableReadStream *stream, SavegameHeader &header) {
+ header._totalFrames = 0;
+
+ // Validate the header Id
+ if (stream->readUint32BE() != MKTAG('G', 'A', 'R', 'G'))
+ return false;
+
+ // Check the savegame version
+ header._version = stream->readByte();
+ if (header._version > SAVEGAME_VERSION)
+ error("Savegame is too recent");
+
+ // Read the interpreter, language, and game Id
+ header._interpType = stream->readByte();
+ header._language = stream->readByte();
+ header._md5 = readString(stream);
+
+ // Read in name
+ header._saveName = readString(stream);
+
+ // Read in save date/time
+ header._year = stream->readUint16LE();
+ header._month = stream->readUint16LE();
+ header._day = stream->readUint16LE();
+ header._hour = stream->readUint16LE();
+ header._minute = stream->readUint16LE();
+ header._totalFrames = stream->readUint32LE();
+
+ return true;
+}
+
+void FileStream::writeSavegameHeader(Common::WriteStream *stream, const Common::String &saveName) {
+ // Write out a savegame header
+ stream->writeUint32BE(MKTAG('G', 'A', 'R', 'G'));
+ stream->writeByte(SAVEGAME_VERSION);
+
+ // Write out intrepreter type, language, and game Id
+ stream->writeByte(g_vm->getInterpreterType());
+ stream->writeByte(g_vm->getLanguage());
+ Common::String md5 = g_vm->getGameMD5();
+ stream->write(md5.c_str(), md5.size());
+ stream->writeByte('\0');
+
+ // Write savegame name
+ stream->write(saveName.c_str(), saveName.size());
+ stream->writeByte('\0');
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ stream->writeUint16LE(td.tm_year + 1900);
+ stream->writeUint16LE(td.tm_mon + 1);
+ stream->writeUint16LE(td.tm_mday);
+ stream->writeUint16LE(td.tm_hour);
+ stream->writeUint16LE(td.tm_min);
+ stream->writeUint32LE(g_vm->_events->getTotalPlayTicks());
+}
+
+/*--------------------------------------------------------------------------*/
+
+Streams::Streams() : _streamList(nullptr), _currentStream(nullptr) {
+}
+
+Streams::~Streams() {
+ while (_streamList)
+ delete _streamList;
+}
+
+FileStream *Streams::openFileStream(frefid_t fref, glui32 fmode, glui32 rock, bool unicode) {
+ FileStream *stream = new FileStream(this, fref, fmode, rock, unicode);
+ addStream(stream);
+ return stream;
+}
+
+WindowStream *Streams::openWindowStream(Window *window) {
+ WindowStream *stream = new WindowStream(this, window);
+ addStream(stream);
+ return stream;
+}
+
+MemoryStream *Streams::openMemoryStream(void *buf, size_t buflen, FileMode mode, uint32 rock, bool unicode) {
+ MemoryStream *stream = new MemoryStream(this, buf, buflen, mode, rock, unicode);
+ addStream(stream);
+ return stream;
+}
+
+void Streams::addStream(Stream *stream) {
+ stream->_next = _streamList;
+ _streamList = stream;
+ if (stream->_next)
+ stream->_next->_prev = stream;
+}
+
+void Streams::removeStream(Stream *stream) {
+ Stream *prev = stream->_prev;
+ Stream *next = stream->_next;
+
+ if (prev)
+ prev->_next = next;
+ else
+ _streamList = next;
+ if (next)
+ next->_prev = prev;
+
+ // Remove the stream as the echo stream of any window
+ for (Windows::iterator i = g_vm->_windows->begin(); i != g_vm->_windows->end(); ++i) {
+ if ((*i)->_echoStream == stream)
+ (*i)->_echoStream = nullptr;
+ }
+}
+
+Stream *Streams::getFirst(uint32 *rock) {
+ if (rock)
+ *rock = _streamList ? _streamList->_rock : 0;
+ return _streamList;
+}
+
+
+frefid_t Streams::createByPrompt(glui32 usage, FileMode fmode, glui32 rock) {
+ switch (usage & fileusage_TypeMask) {
+ case fileusage_SavedGame: {
+ if (fmode == filemode_Write) {
+ // Select a savegame slot
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ Common::String desc = dialog->getResultString();
+ return createRef(slot, desc, usage, rock);
+ }
+ } else if (fmode == filemode_Read) {
+ // Load a savegame slot
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ return createRef(slot, "", usage, rock);
+ }
+ } else {
+ error("Unsupport file mode");
+ }
+ break;
+ }
+
+ case fileusage_Transcript:
+ return createRef("transcript.txt", fmode, rock);
+
+ default:
+ error("Unsupport file mode");
+ break;
+ }
+
+ return nullptr;
+}
+
+frefid_t Streams::createRef(int slot, const Common::String &desc, glui32 usage, glui32 rock) {
+ frefid_t fref = new FileReference();
+ fref->_slotNumber = slot;
+ fref->_description = desc;
+ fref->_textMode = ((usage & fileusage_TextMode) != 0);
+ fref->_fileType = (FileUsage)(usage & fileusage_TypeMask);
+
+ _fileReferences.push_back(FileRefArray::value_type(fref));
+ return fref;
+}
+
+frefid_t Streams::createRef(const Common::String &filename, glui32 usage, glui32 rock) {
+ frefid_t fref = new FileReference();
+ fref->_filename = filename;
+ fref->_textMode = ((usage & fileusage_TextMode) != 0);
+ fref->_fileType = (FileUsage)(usage & fileusage_TypeMask);
+
+ _fileReferences.push_back(FileRefArray::value_type(fref));
+ return fref;
+}
+
+frefid_t Streams::createTemp(glui32 usage, glui32 rock) {
+ return createRef(Common::String::format("%s.tmp", g_vm->getTargetName().c_str()),
+ usage, rock);
+}
+
+frefid_t Streams::createFromRef(frefid_t fref, glui32 usage, glui32 rock) {
+ return createRef(fref->_filename, usage, rock);
+}
+
+void Streams::deleteRef(frefid_t fref) {
+ for (uint idx = 0; idx < _fileReferences.size(); ++idx) {
+ if (_fileReferences[idx].get() == fref) {
+ _fileReferences.remove_at(idx);
+ return;
+ }
+ }
+}
+
+frefid_t Streams::iterate(frefid_t fref, glui32 *rock) {
+ // Find reference following the specified one
+ int index = -1;
+ for (uint idx = 0; idx < _fileReferences.size(); ++idx) {
+ if (fref == nullptr || _fileReferences[idx].get() == fref) {
+ if (idx < (_fileReferences.size() - 1))
+ index = idx + 1;
+ break;
+ }
+ }
+
+ if (index != -1) {
+ if (rock)
+ *rock = _fileReferences[index].get()->_rock;
+ return _fileReferences[index].get();
+ }
+
+ if (rock)
+ *rock = 0;
+ return nullptr;
+}
+
+/*--------------------------------------------------------------------------*/
+
+const Common::String FileReference::getSaveName() const {
+ assert(_slotNumber != -1);
+ return g_vm->getSaveName(_slotNumber);
+}
+
+bool FileReference::exists() const {
+ Common::String filename;
+
+ if (_slotNumber == -1) {
+ if (Common::File::exists(_filename))
+ return true;
+ filename = _filename;
+ } else {
+ filename = getSaveName();
+ }
+
+ // Check for a savegame (or other file in the save folder) with that name
+ Common::InSaveFile *inSave = g_system->getSavefileManager()->openForLoading(filename);
+ bool result = inSave != nullptr;
+ delete inSave;
+ return result;
+}
+
+void FileReference::deleteFile() {
+ Common::String filename = (_slotNumber == -1) ? _filename : getSaveName();
+ g_system->getSavefileManager()->removeSavefile(filename);
+}
+
+} // End of namespace Gargoyle