mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-24 19:45:07 +00:00
1573 lines
35 KiB
C++
1573 lines
35 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "glk/streams.h"
|
|
#include "glk/conf.h"
|
|
#include "glk/events.h"
|
|
#include "glk/glk.h"
|
|
#include "glk/windows.h"
|
|
#include "gui/saveload.h"
|
|
#include "common/file.h"
|
|
#include "common/savefile.h"
|
|
#include "common/translation.h"
|
|
|
|
namespace Glk {
|
|
|
|
Stream::Stream(Streams *streams, bool readable, bool writable, uint rock, bool unicode) :
|
|
_streams(streams), _readable(readable), _writable(writable), _rock(0), _unicode(unicode),
|
|
_readCount(0), _writeCount(0), _prev(nullptr), _next(nullptr) {
|
|
if (g_vm->gli_register_obj)
|
|
_dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Stream);
|
|
}
|
|
|
|
Stream::~Stream() {
|
|
_streams->removeStream(this);
|
|
|
|
if (g_vm->gli_unregister_obj)
|
|
(*g_vm->gli_unregister_obj)(this, gidisp_Class_Stream, _dispRock);
|
|
}
|
|
|
|
Stream *Stream::getNext(uint *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(uint fg, uint bg) {
|
|
if (_writable && g_conf->_styleHint)
|
|
Windows::_forceRedraw = true;
|
|
}
|
|
|
|
void Stream::setReverseVideo(bool reverse) {
|
|
if (_writable && g_conf->_styleHint)
|
|
Windows::_forceRedraw = true;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
WindowStream::~WindowStream() {
|
|
_window->_stream = nullptr;
|
|
}
|
|
|
|
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) {
|
|
uint 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 uint32 *buf, size_t len) {
|
|
uint lx;
|
|
const uint32 *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(uint val) {
|
|
if (!_writable)
|
|
return;
|
|
|
|
if (val >= style_NUMSTYLES)
|
|
val = 0;
|
|
|
|
_window->_attr.style = val;
|
|
if (_window->_echoStream)
|
|
_window->_echoStream->setStyle(val);
|
|
}
|
|
|
|
void WindowStream::setHyperlink(uint linkVal) {
|
|
if (_writable)
|
|
_window->_attr.hyper = linkVal;
|
|
}
|
|
|
|
void WindowStream::setZColors(uint fg, uint bg) {
|
|
if (!_writable || !g_conf->_styleHint)
|
|
return;
|
|
|
|
uint fore = fg, back = bg;
|
|
|
|
if (fg != zcolor_Transparent && fg != zcolor_Cursor) {
|
|
PropFontInfo *info = &g_conf->_propInfo;
|
|
|
|
if (fg == zcolor_Default) {
|
|
_window->_attr.fgset = false;
|
|
_window->_attr.fgcolor = 0;
|
|
Windows::_overrideFgSet = false;
|
|
Windows::_overrideFgVal = 0;
|
|
|
|
info->_moreColor = info->_moreSave;
|
|
info->_caretColor = info->_caretSave;
|
|
info->_linkColor = info->_linkSave;
|
|
} else if (fg != zcolor_Current) {
|
|
_window->_attr.fgset = true;
|
|
_window->_attr.fgcolor = fg;
|
|
Windows::_overrideFgSet = true;
|
|
Windows::_overrideFgVal = fg;
|
|
|
|
info->_moreColor = fore;
|
|
info->_caretColor = fore;
|
|
info->_linkColor = fore;
|
|
}
|
|
}
|
|
|
|
if (/*bg != zcolor_Transparent &&*/ bg != zcolor_Cursor) {
|
|
if (bg == zcolor_Default) {
|
|
_window->_attr.bgset = false;
|
|
_window->_attr.bgcolor = 0;
|
|
Windows::_overrideBgSet = false;
|
|
Windows::_overrideBgVal = 0;
|
|
|
|
g_conf->_windowColor = g_conf->_windowSave;
|
|
g_conf->_borderColor = g_conf->_borderSave;
|
|
} else if (bg != zcolor_Current) {
|
|
_window->_attr.bgset = true;
|
|
_window->_attr.bgcolor = bg;
|
|
Windows::_overrideBgSet = true;
|
|
Windows::_overrideBgVal = bg;
|
|
|
|
g_conf->_windowColor = back;
|
|
g_conf->_borderColor = back;
|
|
}
|
|
}
|
|
|
|
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, uint 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;
|
|
|
|
if (g_vm->gli_register_arr)
|
|
_arrayRock = (*g_vm->gli_register_arr)(buf, buflen, unicode ? "&+#!Iu" : "&+#!Cn");
|
|
}
|
|
|
|
MemoryStream::~MemoryStream() {
|
|
if (g_vm->gli_unregister_arr) {
|
|
const char *typedesc = _unicode ? "&+#!Iu" : "&+#!Cn";
|
|
(*g_vm->gli_unregister_arr)(_buf, _bufLen, typedesc, _arrayRock);
|
|
}
|
|
}
|
|
|
|
void MemoryStream::putChar(unsigned char ch) {
|
|
if (!_writable)
|
|
return;
|
|
++_writeCount;
|
|
|
|
if (_bufPtr < _bufEnd) {
|
|
if (_unicode) {
|
|
*((uint32 *)_bufPtr) = ch;
|
|
_bufPtr = ((uint32 *)_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) {
|
|
*((uint32 *)_bufPtr) = ch;
|
|
_bufPtr = ((uint32 *)_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 {
|
|
uint32 *bp = (uint32 *)_bufPtr;
|
|
if (bp + len > (uint32 *)_bufEnd) {
|
|
lx = (bp + len) - (uint32 *)_bufEnd;
|
|
if (lx < len)
|
|
len -= lx;
|
|
else
|
|
len = 0;
|
|
}
|
|
if (len) {
|
|
uint i;
|
|
for (i = 0; i < len; i++)
|
|
bp[i] = buf[i];
|
|
bp += len;
|
|
if (bp > (uint32 *)_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) {
|
|
uint i;
|
|
for (i = 0; i < len; i++) {
|
|
uint32 ch = buf[i];
|
|
if (ch > 0xff)
|
|
ch = '?';
|
|
bp[i] = (unsigned char)ch;
|
|
}
|
|
bp += len;
|
|
if (bp > (unsigned char *)_bufEof)
|
|
_bufEof = bp;
|
|
}
|
|
_bufPtr = bp;
|
|
} else {
|
|
uint32 *bp = (uint32 *)_bufPtr;
|
|
if (bp + len > (uint32 *)_bufEnd) {
|
|
lx = (bp + len) - (uint32 *)_bufEnd;
|
|
if (lx < len)
|
|
len -= lx;
|
|
else
|
|
len = 0;
|
|
}
|
|
if (len) {
|
|
memmove(bp, buf, len * 4);
|
|
bp += len;
|
|
if (bp > (uint32 *)_bufEof)
|
|
_bufEof = bp;
|
|
}
|
|
_bufPtr = bp;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint MemoryStream::getPosition() const {
|
|
if (_unicode)
|
|
return ((uint32 *)_bufPtr - (uint32 *)_buf);
|
|
else
|
|
return ((unsigned char *)_bufPtr - (unsigned char *)_buf);
|
|
}
|
|
|
|
void MemoryStream::setPosition(int pos, uint 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 = ((uint32 *)_bufPtr - (uint32 *)_buf) + pos;
|
|
else if (seekMode == seekmode_End)
|
|
pos = ((uint32 *)_bufEof - (uint32 *)_buf) + pos;
|
|
|
|
if (pos < 0)
|
|
pos = 0;
|
|
if (pos > ((uint32 *)_bufEof - (uint32 *)_buf))
|
|
pos = ((uint32 *)_bufEof - (uint32 *)_buf);
|
|
_bufPtr = (uint32 *)_buf + pos;
|
|
}
|
|
}
|
|
|
|
int 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 {
|
|
uint32 ch;
|
|
ch = *((uint32 *)_bufPtr);
|
|
_bufPtr = ((uint32 *)_bufPtr) + 1;
|
|
_readCount++;
|
|
if (ch > 0xff)
|
|
ch = '?';
|
|
return ch;
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int 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 {
|
|
uint32 ch;
|
|
ch = *((uint32 *)_bufPtr);
|
|
_bufPtr = ((uint32 *)_bufPtr) + 1;
|
|
_readCount++;
|
|
return ch;
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
uint MemoryStream::getBuffer(char *buf, uint 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) {
|
|
uint 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 {
|
|
uint32 *bp = (uint32 *)_bufPtr;
|
|
if (bp + len > (uint32 *)_bufEnd) {
|
|
uint lx;
|
|
lx = (bp + len) - (uint32 *)_bufEnd;
|
|
if (lx < len)
|
|
len -= lx;
|
|
else
|
|
len = 0;
|
|
}
|
|
if (len) {
|
|
uint i;
|
|
for (i = 0; i < len; i++) {
|
|
uint32 ch = *bp++;
|
|
if (ch > 0xff)
|
|
ch = '?';
|
|
*buf++ = (char)ch;
|
|
}
|
|
if (bp > (uint32 *)_bufEof)
|
|
_bufEof = bp;
|
|
}
|
|
|
|
_readCount += len;
|
|
_bufPtr = bp;
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
uint MemoryStream::getBufferUni(uint32 *buf, uint 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) {
|
|
uint lx;
|
|
lx = (bp + len) - (unsigned char *)_bufEnd;
|
|
if (lx < len)
|
|
len -= lx;
|
|
else
|
|
len = 0;
|
|
}
|
|
if (len) {
|
|
uint 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 {
|
|
uint32 *bp = (uint32 *)_bufPtr;
|
|
if (bp + len > (uint32 *)_bufEnd) {
|
|
uint lx;
|
|
lx = (bp + len) - (uint32 *)_bufEnd;
|
|
if (lx < len)
|
|
len -= lx;
|
|
else
|
|
len = 0;
|
|
}
|
|
if (len) {
|
|
memcpy(buf, bp, len * 4);
|
|
bp += len;
|
|
if (bp > (uint32 *)_bufEof)
|
|
_bufEof = bp;
|
|
}
|
|
_readCount += len;
|
|
_bufPtr = bp;
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
uint MemoryStream::getLine(char *buf, uint len) {
|
|
uint 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++) {
|
|
uint32 ch;
|
|
ch = ((uint32 *)_bufPtr)[lx];
|
|
if (ch >= 0x100)
|
|
ch = '?';
|
|
buf[lx] = (char)ch;
|
|
gotNewline = (ch == '\n');
|
|
}
|
|
|
|
buf[lx] = '\0';
|
|
_bufPtr = ((uint32 *)_bufPtr) + lx;
|
|
}
|
|
|
|
_readCount += lx;
|
|
return lx;
|
|
}
|
|
|
|
uint MemoryStream::getLineUni(uint32 *ubuf, uint 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 ((uint32 *)_bufPtr + len > (uint32 *)_bufEnd) {
|
|
lx = ((uint32 *)_bufPtr + len) - (uint32 *)_bufEnd;
|
|
if (lx < (int)len)
|
|
len -= lx;
|
|
else
|
|
len = 0;
|
|
}
|
|
}
|
|
gotNewline = false;
|
|
for (lx = 0; lx < (int)len && !gotNewline; lx++) {
|
|
uint32 ch;
|
|
ch = ((uint32 *)_bufPtr)[lx];
|
|
ubuf[lx] = ch;
|
|
gotNewline = (ch == '\n');
|
|
}
|
|
ubuf[lx] = '\0';
|
|
_bufPtr = ((uint32 *)_bufPtr) + lx;
|
|
}
|
|
|
|
_readCount += lx;
|
|
return lx;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void IOStream::ensureOp(FileMode mode) {
|
|
// No implementation
|
|
}
|
|
|
|
void IOStream::putChar(unsigned char ch) {
|
|
if (!_writable)
|
|
return;
|
|
++_writeCount;
|
|
|
|
ensureOp(filemode_Write);
|
|
if (!_unicode) {
|
|
_outStream->writeByte(ch);
|
|
} else if (_textFile) {
|
|
putCharUtf8((uint)ch);
|
|
} else {
|
|
_outStream->writeUint32BE(ch);
|
|
}
|
|
|
|
_outStream->flush();
|
|
}
|
|
|
|
void IOStream::putCharUni(uint32 ch) {
|
|
if (!_writable)
|
|
return;
|
|
++_writeCount;
|
|
|
|
ensureOp(filemode_Write);
|
|
if (!_unicode) {
|
|
if (ch >= 0x100)
|
|
ch = '?';
|
|
_outStream->writeByte(ch);
|
|
} else if (_textFile) {
|
|
putCharUtf8(ch);
|
|
} else {
|
|
_outStream->writeUint32BE(ch);
|
|
}
|
|
|
|
_outStream->flush();
|
|
}
|
|
|
|
void IOStream::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) {
|
|
_outStream->writeByte(ch);
|
|
} else if (_textFile) {
|
|
putCharUtf8((uint)ch);
|
|
} else {
|
|
_outStream->writeUint32BE(ch);
|
|
}
|
|
}
|
|
|
|
_outStream->flush();
|
|
}
|
|
|
|
void IOStream::putBufferUni(const uint32 *buf, size_t len) {
|
|
if (!_writable)
|
|
return;
|
|
_writeCount += len;
|
|
|
|
|
|
ensureOp(filemode_Write);
|
|
for (size_t lx = 0; lx < len; lx++) {
|
|
uint32 ch = buf[lx];
|
|
if (!_unicode) {
|
|
if (ch >= 0x100)
|
|
ch = '?';
|
|
_outStream->writeByte(ch);
|
|
} else if (_textFile) {
|
|
putCharUtf8(ch);
|
|
} else {
|
|
_outStream->writeUint32BE(ch);
|
|
}
|
|
}
|
|
|
|
_outStream->flush();
|
|
}
|
|
|
|
void IOStream::putCharUtf8(uint val) {
|
|
if (val < 0x80) {
|
|
_outStream->writeByte(val);
|
|
} else if (val < 0x800) {
|
|
_outStream->writeByte((0xC0 | ((val & 0x7C0) >> 6)));
|
|
_outStream->writeByte((0x80 | (val & 0x03F)));
|
|
} else if (val < 0x10000) {
|
|
_outStream->writeByte((0xE0 | ((val & 0xF000) >> 12)));
|
|
_outStream->writeByte((0x80 | ((val & 0x0FC0) >> 6)));
|
|
_outStream->writeByte((0x80 | (val & 0x003F)));
|
|
} else if (val < 0x200000) {
|
|
_outStream->writeByte((0xF0 | ((val & 0x1C0000) >> 18)));
|
|
_outStream->writeByte((0x80 | ((val & 0x03F000) >> 12)));
|
|
_outStream->writeByte((0x80 | ((val & 0x000FC0) >> 6)));
|
|
_outStream->writeByte((0x80 | (val & 0x00003F)));
|
|
} else {
|
|
_outStream->writeByte('?');
|
|
}
|
|
}
|
|
|
|
int IOStream::getCharUtf8() {
|
|
uint res;
|
|
uint 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 '?';
|
|
}
|
|
|
|
uint IOStream::getPosition() const {
|
|
return _outStream ? _outStream->pos() : _inStream->pos();
|
|
}
|
|
|
|
void IOStream::setPosition(int pos, uint seekMode) {
|
|
_lastOp = 0;
|
|
if (_unicode)
|
|
pos *= 4;
|
|
|
|
if (_inStream) {
|
|
_inStream->seek(pos, SEEK_SET);
|
|
} else {
|
|
Common::SeekableWriteStream *ws =
|
|
dynamic_cast<Common::SeekableWriteStream *>(_outStream);
|
|
|
|
if (ws)
|
|
ws->seek(pos, SEEK_SET);
|
|
else
|
|
error("seek not supported for writing files");
|
|
}
|
|
}
|
|
|
|
int IOStream::getChar() {
|
|
if (!_readable)
|
|
return -1;
|
|
|
|
ensureOp(filemode_Read);
|
|
int res;
|
|
if (!_unicode) {
|
|
res = _inStream->eos() ? -1 : _inStream->readByte();
|
|
} else if (_textFile) {
|
|
res = getCharUtf8();
|
|
} else {
|
|
uint32 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 (int)res;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int IOStream::getCharUni() {
|
|
if (!_readable)
|
|
return -1;
|
|
|
|
ensureOp(filemode_Read);
|
|
int res;
|
|
if (!_unicode) {
|
|
res = _inStream->readByte();
|
|
} else if (_textFile) {
|
|
res = getCharUtf8();
|
|
} else {
|
|
uint32 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 (int)res;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
uint IOStream::getBuffer(char *buf, uint len) {
|
|
ensureOp(filemode_Read);
|
|
if (!_unicode) {
|
|
uint res;
|
|
res = _inStream->read(buf, len);
|
|
_readCount += res;
|
|
return res;
|
|
} else if (_textFile) {
|
|
uint lx;
|
|
for (lx = 0; lx < len; lx++) {
|
|
uint32 ch;
|
|
ch = getCharUtf8();
|
|
if (ch == (uint)-1)
|
|
break;
|
|
_readCount++;
|
|
if (ch >= 0x100)
|
|
ch = '?';
|
|
buf[lx] = (char)ch;
|
|
}
|
|
return lx;
|
|
} else {
|
|
uint lx;
|
|
for (lx = 0; lx < len; lx++) {
|
|
int res;
|
|
uint32 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;
|
|
}
|
|
}
|
|
|
|
uint IOStream::getBufferUni(uint32 *buf, uint len) {
|
|
if (!_readable)
|
|
return 0;
|
|
|
|
ensureOp(filemode_Read);
|
|
if (!_unicode) {
|
|
uint lx;
|
|
for (lx = 0; lx < len; lx++) {
|
|
int res;
|
|
uint32 ch;
|
|
res = _inStream->readByte();
|
|
if (res == -1)
|
|
break;
|
|
ch = (res & 0xFF);
|
|
_readCount++;
|
|
buf[lx] = ch;
|
|
}
|
|
return lx;
|
|
} else if (_textFile) {
|
|
uint lx;
|
|
for (lx = 0; lx < len; lx++) {
|
|
uint32 ch;
|
|
ch = getCharUtf8();
|
|
if (ch == (uint)-1)
|
|
break;
|
|
_readCount++;
|
|
buf[lx] = ch;
|
|
}
|
|
return lx;
|
|
} else {
|
|
uint lx;
|
|
for (lx = 0; lx < len; lx++) {
|
|
int res;
|
|
uint32 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;
|
|
}
|
|
}
|
|
|
|
uint IOStream::getLine(char *buf, uint len) {
|
|
uint 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++) {
|
|
uint32 ch;
|
|
ch = getCharUtf8();
|
|
if (ch == (uint)-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;
|
|
uint32 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;
|
|
}
|
|
}
|
|
|
|
uint IOStream::getLineUni(uint32 *ubuf, uint 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;
|
|
uint32 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++) {
|
|
uint32 ch;
|
|
ch = getCharUtf8();
|
|
if (ch == (uint)-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;
|
|
uint32 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;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
FileStream::FileStream(Streams *streams, frefid_t fref, uint fmode, uint rock, bool unicode) :
|
|
IOStream(streams, fmode == filemode_Read, fmode != filemode_Read, rock, unicode),
|
|
_inSave(nullptr), _outSave(nullptr) {
|
|
|
|
_textFile = fref->_textMode;
|
|
Common::String fname = fref->_slotNumber == -1 ? fref->_filename : fref->getSaveName();
|
|
|
|
if (fmode == filemode_Write || fmode == filemode_ReadWrite || fmode == filemode_WriteAppend) {
|
|
_outSave = g_system->getSavefileManager()->openForSaving(fname, false);
|
|
if (!_outSave)
|
|
error("Could open file for writing - %s", fname.c_str());
|
|
setStream(_outSave);
|
|
|
|
} else if (fmode == filemode_Read) {
|
|
if (_file.open(fname)) {
|
|
setStream(&_file);
|
|
} else {
|
|
_inSave = g_system->getSavefileManager()->openForLoading(fname);
|
|
setStream(_inSave);
|
|
|
|
if (!_inSave)
|
|
error("Could not open for reading - %s", fname.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
FileStream::~FileStream() {
|
|
_file.close();
|
|
delete _inSave;
|
|
if (_outSave) {
|
|
_outSave->finalize();
|
|
delete _outSave;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
Streams::Streams() : _streamList(nullptr), _currentStream(nullptr) {
|
|
}
|
|
|
|
Streams::~Streams() {
|
|
for (Stream *currStream = _streamList, *nextStream; currStream; currStream = nextStream) {
|
|
nextStream = currStream->_next;
|
|
delete currStream;
|
|
}
|
|
}
|
|
|
|
FileStream *Streams::openFileStream(frefid_t fref, uint fmode, uint rock, bool unicode) {
|
|
FileStream *stream = new FileStream(this, fref, fmode, rock, unicode);
|
|
addStream(stream);
|
|
return stream;
|
|
}
|
|
|
|
IOStream *Streams::openStream(Common::SeekableReadStream *rs, uint rock) {
|
|
IOStream *stream = new IOStream(this, rs, rock);
|
|
addStream(stream);
|
|
return stream;
|
|
}
|
|
|
|
IOStream *Streams::openStream(Common::WriteStream *ws, uint rock) {
|
|
IOStream *stream = new IOStream(this, ws, rock);
|
|
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, uint 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;
|
|
}
|
|
|
|
if (_currentStream == stream)
|
|
_currentStream = nullptr;
|
|
}
|
|
|
|
Stream *Streams::getFirst(uint *rock) {
|
|
if (rock)
|
|
*rock = _streamList ? _streamList->_rock : 0;
|
|
return _streamList;
|
|
}
|
|
|
|
|
|
frefid_t Streams::createByPrompt(uint usage, FileMode fmode, uint 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, uint usage, uint 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, uint usage, uint 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(uint usage, uint rock) {
|
|
return createRef(Common::String::format("%s.tmp", g_vm->getTargetName().c_str()),
|
|
usage, rock);
|
|
}
|
|
|
|
frefid_t Streams::createFromRef(frefid_t fref, uint usage, uint 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, uint *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;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
FileReference::FileReference() : _rock(0), _slotNumber(-1), _fileType(fileusage_Data), _textMode(false) {
|
|
if (g_vm->gli_register_obj)
|
|
_dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Fileref);
|
|
}
|
|
|
|
FileReference::FileReference(int slot, const Common::String &desc, uint usage, uint rock) :
|
|
_rock(rock), _slotNumber(slot), _description(desc),
|
|
_fileType((FileUsage)(usage & fileusage_TypeMask)), _textMode(usage & fileusage_TextMode) {
|
|
if (g_vm->gli_register_obj)
|
|
_dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Fileref);
|
|
}
|
|
|
|
FileReference::~FileReference() {
|
|
if (g_vm->gli_unregister_obj)
|
|
(*g_vm->gli_unregister_obj)(this, gidisp_Class_Fileref, _dispRock);
|
|
}
|
|
|
|
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 Glk
|