1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software{} you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation{} either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY{} without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program{} if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/streams.h"
24 #include "glk/conf.h"
25 #include "glk/events.h"
26 #include "glk/glk.h"
27 #include "glk/windows.h"
28 #include "gui/saveload.h"
29 #include "common/file.h"
30 #include "common/savefile.h"
31 #include "common/translation.h"
32
33 namespace Glk {
34
Stream(Streams * streams,bool readable,bool writable,uint rock,bool unicode)35 Stream::Stream(Streams *streams, bool readable, bool writable, uint rock, bool unicode) :
36 _streams(streams), _readable(readable), _writable(writable), _rock(0), _unicode(unicode),
37 _readCount(0), _writeCount(0), _prev(nullptr), _next(nullptr) {
38 if (g_vm->gli_register_obj)
39 _dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Stream);
40 }
41
~Stream()42 Stream::~Stream() {
43 _streams->removeStream(this);
44
45 if (g_vm->gli_unregister_obj)
46 (*g_vm->gli_unregister_obj)(this, gidisp_Class_Stream, _dispRock);
47 }
48
getNext(uint * rock) const49 Stream *Stream::getNext(uint *rock) const {
50 Stream *stream = _next;
51 if (rock)
52 *rock = stream ? stream->_rock : 0;
53 return stream;
54 }
55
fillResult(StreamResult * result)56 void Stream::fillResult(StreamResult *result) {
57 if (result) {
58 result->_readCount = _readCount;
59 result->_writeCount = _writeCount;
60 }
61 }
62
close(StreamResult * result)63 void Stream::close(StreamResult *result) {
64 // Get the read/write totals
65 fillResult(result);
66
67 // Remove the stream
68 delete this;
69 }
70
setZColors(uint fg,uint bg)71 void Stream::setZColors(uint fg, uint bg) {
72 if (_writable && g_conf->_styleHint)
73 Windows::_forceRedraw = true;
74 }
75
setReverseVideo(bool reverse)76 void Stream::setReverseVideo(bool reverse) {
77 if (_writable && g_conf->_styleHint)
78 Windows::_forceRedraw = true;
79 }
80
81 /*--------------------------------------------------------------------------*/
82
~WindowStream()83 WindowStream::~WindowStream() {
84 _window->_stream = nullptr;
85 }
86
close(StreamResult * result)87 void WindowStream::close(StreamResult *result) {
88 warning("cannot close window stream");
89 }
90
putChar(unsigned char ch)91 void WindowStream::putChar(unsigned char ch) {
92 if (!_writable)
93 return;
94 ++_writeCount;
95
96 if (_window->_lineRequest || _window->_lineRequestUni) {
97 if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
98 _window->cancelLineEvent(nullptr);
99 g_vm->_events->_forceClick = false;
100 } else {
101 warning("putChar: window has pending line request");
102 }
103 }
104
105 _window->putCharUni(ch);
106 if (_window->_echoStream)
107 _window->_echoStream->putChar(ch);
108 }
109
putCharUni(uint32 ch)110 void WindowStream::putCharUni(uint32 ch) {
111 if (!_writable)
112 return;
113 ++_writeCount;
114
115 if (_window->_lineRequest || _window->_lineRequestUni) {
116 if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
117 _window->cancelLineEvent(nullptr);
118 g_vm->_events->_forceClick = false;
119 } else {
120 warning("putCharUni: window has pending line request");
121 }
122 }
123
124 _window->putCharUni(ch);
125 if (_window->_echoStream)
126 _window->_echoStream->putCharUni(ch);
127 }
128
putBuffer(const char * buf,size_t len)129 void WindowStream::putBuffer(const char *buf, size_t len) {
130 if (!_writable)
131 return;
132 _writeCount += len;
133
134 if (_window->_lineRequest || _window->_lineRequestUni) {
135 if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
136 _window->cancelLineEvent(nullptr);
137 g_vm->_events->_forceClick = false;
138 } else {
139 warning("putBuffer: window has pending line request");
140 }
141 }
142
143 for (size_t lx = 0; lx < len; lx++, buf++)
144 _window->putCharUni(*buf);
145 if (_window->_echoStream)
146 _window->_echoStream->putBuffer(buf, len);
147 }
148
putBufferUni(const uint32 * buf,size_t len)149 void WindowStream::putBufferUni(const uint32 *buf, size_t len) {
150 if (!_writable)
151 return;
152 _writeCount += len;
153
154 if (_window->_lineRequest || _window->_lineRequestUni) {
155 if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
156 _window->cancelLineEvent(nullptr);
157 g_vm->_events->_forceClick = false;
158 } else {
159 warning("putBuffer: window has pending line request");
160 }
161 }
162
163 for (size_t lx = 0; lx < len; lx++, buf++)
164 _window->putCharUni(*buf);
165 if (_window->_echoStream)
166 _window->_echoStream->putBufferUni(buf, len);
167 }
168
unputBuffer(const char * buf,size_t len)169 void WindowStream::unputBuffer(const char *buf, size_t len) {
170 uint lx;
171 const char *cx;
172
173 if (!_writable)
174 return;
175
176 if (_window->_lineRequest || _window->_lineRequestUni) {
177 if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
178 _window->cancelLineEvent(nullptr);
179 g_vm->_events->_forceClick = false;
180 } else {
181 warning("unput_buffer: window has pending line request");
182 return;
183 }
184 }
185
186 for (lx = 0, cx = buf + len - 1; lx < len; lx++, cx--) {
187 if (!_window->unputCharUni(*cx))
188 break;
189 _writeCount--;
190 }
191 if (_window->_echoStream)
192 _window->_echoStream->unputBuffer(buf, len);
193 }
194
unputBufferUni(const uint32 * buf,size_t len)195 void WindowStream::unputBufferUni(const uint32 *buf, size_t len) {
196 uint lx;
197 const uint32 *cx;
198
199 if (!_writable)
200 return;
201
202 if (_window->_lineRequest || _window->_lineRequestUni) {
203 if (g_conf->_safeClicks && g_vm->_events->_forceClick) {
204 _window->cancelLineEvent(nullptr);
205 g_vm->_events->_forceClick = false;
206 } else {
207 warning("unput_buffer: window has pending line request");
208 return;
209 }
210 }
211
212 for (lx = 0, cx = buf + len - 1; lx < len; lx++, cx--) {
213 if (!_window->unputCharUni(*cx))
214 break;
215 _writeCount--;
216 }
217
218 if (_window->_echoStream)
219 _window->_echoStream->unputBufferUni(buf, len);
220 }
221
setStyle(uint val)222 void WindowStream::setStyle(uint val) {
223 if (!_writable)
224 return;
225
226 if (val >= style_NUMSTYLES)
227 val = 0;
228
229 _window->_attr.style = val;
230 if (_window->_echoStream)
231 _window->_echoStream->setStyle(val);
232 }
233
setHyperlink(uint linkVal)234 void WindowStream::setHyperlink(uint linkVal) {
235 if (_writable)
236 _window->_attr.hyper = linkVal;
237 }
238
setZColors(uint fg,uint bg)239 void WindowStream::setZColors(uint fg, uint bg) {
240 if (!_writable || !g_conf->_styleHint)
241 return;
242
243 uint fore = fg, back = bg;
244
245 if (fg != zcolor_Transparent && fg != zcolor_Cursor) {
246 PropFontInfo *info = &g_conf->_propInfo;
247
248 if (fg == zcolor_Default) {
249 _window->_attr.fgset = false;
250 _window->_attr.fgcolor = 0;
251 Windows::_overrideFgSet = false;
252 Windows::_overrideFgVal = 0;
253
254 info->_moreColor = info->_moreSave;
255 info->_caretColor = info->_caretSave;
256 info->_linkColor = info->_linkSave;
257 } else if (fg != zcolor_Current) {
258 _window->_attr.fgset = true;
259 _window->_attr.fgcolor = fg;
260 Windows::_overrideFgSet = true;
261 Windows::_overrideFgVal = fg;
262
263 info->_moreColor = fore;
264 info->_caretColor = fore;
265 info->_linkColor = fore;
266 }
267 }
268
269 if (/*bg != zcolor_Transparent &&*/ bg != zcolor_Cursor) {
270 if (bg == zcolor_Default) {
271 _window->_attr.bgset = false;
272 _window->_attr.bgcolor = 0;
273 Windows::_overrideBgSet = false;
274 Windows::_overrideBgVal = 0;
275
276 g_conf->_windowColor = g_conf->_windowSave;
277 g_conf->_borderColor = g_conf->_borderSave;
278 } else if (bg != zcolor_Current) {
279 _window->_attr.bgset = true;
280 _window->_attr.bgcolor = bg;
281 Windows::_overrideBgSet = true;
282 Windows::_overrideBgVal = bg;
283
284 g_conf->_windowColor = back;
285 g_conf->_borderColor = back;
286 }
287 }
288
289 Windows::_overrideReverse = !(fg == zcolor_Default && bg == zcolor_Default);
290 Windows::_forceRedraw = true;
291
292 if (_window->_echoStream)
293 _window->_echoStream->setZColors(fg, bg);
294 }
295
setReverseVideo(bool reverse)296 void WindowStream::setReverseVideo(bool reverse) {
297 if (!_writable || !g_conf->_styleHint)
298 return;
299
300 _window->_attr.reverse = reverse;
301 if (_window->_echoStream)
302 _window->_echoStream->setReverseVideo(reverse);
303
304 Windows::_forceRedraw = true;
305 }
306
307 /*--------------------------------------------------------------------------*/
308
MemoryStream(Streams * streams,void * buf,size_t buflen,FileMode mode,uint rock,bool unicode)309 MemoryStream::MemoryStream(Streams *streams, void *buf, size_t buflen, FileMode mode, uint rock, bool unicode) :
310 Stream(streams, mode != filemode_Write, mode != filemode_Read, rock, unicode),
311 _buf(buf), _bufLen(buflen), _bufPtr(buf) {
312 assert(_buf || !_bufLen);
313 assert(mode == filemode_Read || mode == filemode_Write || mode == filemode_ReadWrite);
314
315 if (unicode)
316 _bufEnd = (uint32 *)buf + buflen;
317 else
318 _bufEnd = (byte *)buf + buflen;
319 _bufEof = mode == filemode_Write ? _buf : _bufEnd;
320
321 if (g_vm->gli_register_arr)
322 _arrayRock = (*g_vm->gli_register_arr)(buf, buflen, unicode ? "&+#!Iu" : "&+#!Cn");
323 }
324
~MemoryStream()325 MemoryStream::~MemoryStream() {
326 if (g_vm->gli_unregister_arr) {
327 const char *typedesc = _unicode ? "&+#!Iu" : "&+#!Cn";
328 (*g_vm->gli_unregister_arr)(_buf, _bufLen, typedesc, _arrayRock);
329 }
330 }
331
putChar(unsigned char ch)332 void MemoryStream::putChar(unsigned char ch) {
333 if (!_writable)
334 return;
335 ++_writeCount;
336
337 if (_bufPtr < _bufEnd) {
338 if (_unicode) {
339 *((uint32 *)_bufPtr) = ch;
340 _bufPtr = ((uint32 *)_bufPtr) + 1;
341 } else {
342 *((unsigned char *)_bufPtr) = ch;
343 _bufPtr = ((unsigned char *)_bufPtr) + 1;
344 }
345
346 if (_bufPtr > _bufEof)
347 _bufEof = _bufPtr;
348 }
349 }
350
putCharUni(uint32 ch)351 void MemoryStream::putCharUni(uint32 ch) {
352 if (!_writable)
353 return;
354 ++_writeCount;
355
356 if (_bufPtr < _bufEnd) {
357 if (_unicode) {
358 *((uint32 *)_bufPtr) = ch;
359 _bufPtr = ((uint32 *)_bufPtr) + 1;
360 } else {
361 *((unsigned char *)_bufPtr) = (unsigned char)ch;
362 _bufPtr = ((unsigned char *)_bufPtr) + 1;
363 }
364 if (_bufPtr > _bufEof)
365 _bufEof = _bufPtr;
366 }
367 }
368
putBuffer(const char * buf,size_t len)369 void MemoryStream::putBuffer(const char *buf, size_t len) {
370 size_t lx;
371
372 if (!_writable)
373 return;
374 _writeCount += len;
375
376 if (_bufPtr >= _bufEnd) {
377 len = 0;
378 } else {
379 if (!_unicode) {
380 unsigned char *bp = (unsigned char *)_bufPtr;
381 if (bp + len > (unsigned char *)_bufEnd) {
382 lx = (bp + len) - (unsigned char *)_bufEnd;
383 if (lx < len)
384 len -= lx;
385 else
386 len = 0;
387 }
388 if (len) {
389 memmove(bp, buf, len);
390 bp += len;
391 if (bp > (unsigned char *)_bufEof)
392 _bufEof = bp;
393 }
394 _bufPtr = bp;
395 } else {
396 uint32 *bp = (uint32 *)_bufPtr;
397 if (bp + len > (uint32 *)_bufEnd) {
398 lx = (bp + len) - (uint32 *)_bufEnd;
399 if (lx < len)
400 len -= lx;
401 else
402 len = 0;
403 }
404 if (len) {
405 uint i;
406 for (i = 0; i < len; i++)
407 bp[i] = buf[i];
408 bp += len;
409 if (bp > (uint32 *)_bufEof)
410 _bufEof = bp;
411 }
412 _bufPtr = bp;
413 }
414 }
415 }
416
putBufferUni(const uint32 * buf,size_t len)417 void MemoryStream::putBufferUni(const uint32 *buf, size_t len) {
418 size_t lx;
419
420 if (!_writable)
421 return;
422 _writeCount += len;
423
424 if (_bufPtr >= _bufEnd) {
425 len = 0;
426 } else {
427 if (!_unicode) {
428 unsigned char *bp = (unsigned char *)_bufPtr;
429 if (bp + len > (unsigned char *)_bufEnd) {
430 lx = (bp + len) - (unsigned char *)_bufEnd;
431 if (lx < len)
432 len -= lx;
433 else
434 len = 0;
435 }
436 if (len) {
437 uint i;
438 for (i = 0; i < len; i++) {
439 uint32 ch = buf[i];
440 if (ch > 0xff)
441 ch = '?';
442 bp[i] = (unsigned char)ch;
443 }
444 bp += len;
445 if (bp > (unsigned char *)_bufEof)
446 _bufEof = bp;
447 }
448 _bufPtr = bp;
449 } else {
450 uint32 *bp = (uint32 *)_bufPtr;
451 if (bp + len > (uint32 *)_bufEnd) {
452 lx = (bp + len) - (uint32 *)_bufEnd;
453 if (lx < len)
454 len -= lx;
455 else
456 len = 0;
457 }
458 if (len) {
459 memmove(bp, buf, len * 4);
460 bp += len;
461 if (bp > (uint32 *)_bufEof)
462 _bufEof = bp;
463 }
464 _bufPtr = bp;
465 }
466 }
467 }
468
getPosition() const469 uint MemoryStream::getPosition() const {
470 if (_unicode)
471 return ((uint32 *)_bufPtr - (uint32 *)_buf);
472 else
473 return ((unsigned char *)_bufPtr - (unsigned char *)_buf);
474 }
475
setPosition(int pos,uint seekMode)476 void MemoryStream::setPosition(int pos, uint seekMode) {
477 if (!_unicode) {
478 if (seekMode == seekmode_Current)
479 pos = ((unsigned char *)_bufPtr - (unsigned char *)_buf) + pos;
480 else if (seekMode == seekmode_End)
481 pos = ((unsigned char *)_bufEof - (unsigned char *)_buf) + pos;
482 else {
483 // pos = pos
484 }
485
486 if (pos < 0)
487 pos = 0;
488 if (pos > ((unsigned char *)_bufEof - (unsigned char *)_buf))
489 pos = ((unsigned char *)_bufEof - (unsigned char *)_buf);
490 _bufPtr = (unsigned char *)_buf + pos;
491 } else {
492 if (seekMode == seekmode_Current)
493 pos = ((uint32 *)_bufPtr - (uint32 *)_buf) + pos;
494 else if (seekMode == seekmode_End)
495 pos = ((uint32 *)_bufEof - (uint32 *)_buf) + pos;
496
497 if (pos < 0)
498 pos = 0;
499 if (pos > ((uint32 *)_bufEof - (uint32 *)_buf))
500 pos = ((uint32 *)_bufEof - (uint32 *)_buf);
501 _bufPtr = (uint32 *)_buf + pos;
502 }
503 }
504
getChar()505 int MemoryStream::getChar() {
506 if (!_readable)
507 return -1;
508
509 if (_bufPtr < _bufEnd) {
510 if (!_unicode) {
511 unsigned char ch;
512 ch = *((unsigned char *)_bufPtr);
513 _bufPtr = ((unsigned char *)_bufPtr) + 1;
514 _readCount++;
515 return ch;
516 } else {
517 uint32 ch;
518 ch = *((uint32 *)_bufPtr);
519 _bufPtr = ((uint32 *)_bufPtr) + 1;
520 _readCount++;
521 if (ch > 0xff)
522 ch = '?';
523 return ch;
524 }
525 } else {
526 return -1;
527 }
528 }
529
getCharUni()530 int MemoryStream::getCharUni() {
531 if (!_readable)
532 return -1;
533
534 if (_bufPtr < _bufEnd) {
535 if (!_unicode) {
536 unsigned char ch;
537 ch = *((unsigned char *)_bufPtr);
538 _bufPtr = ((unsigned char *)_bufPtr) + 1;
539 _readCount++;
540 return ch;
541 } else {
542 uint32 ch;
543 ch = *((uint32 *)_bufPtr);
544 _bufPtr = ((uint32 *)_bufPtr) + 1;
545 _readCount++;
546 return ch;
547 }
548 } else {
549 return -1;
550 }
551 }
552
getBuffer(char * buf,uint len)553 uint MemoryStream::getBuffer(char *buf, uint len) {
554 if (!_readable)
555 return 0;
556
557 if (_bufPtr >= _bufEnd) {
558 len = 0;
559 } else {
560 if (!_unicode) {
561 unsigned char *bp = (unsigned char *)_bufPtr;
562 if (bp + len > (unsigned char *)_bufEnd) {
563 uint lx;
564 lx = (bp + len) - (unsigned char *)_bufEnd;
565 if (lx < len)
566 len -= lx;
567 else
568 len = 0;
569 }
570
571 if (len) {
572 memcpy(buf, bp, len);
573 bp += len;
574 if (bp > (unsigned char *)_bufEof)
575 _bufEof = bp;
576 }
577
578 _readCount += len;
579 _bufPtr = bp;
580 } else {
581 uint32 *bp = (uint32 *)_bufPtr;
582 if (bp + len > (uint32 *)_bufEnd) {
583 uint lx;
584 lx = (bp + len) - (uint32 *)_bufEnd;
585 if (lx < len)
586 len -= lx;
587 else
588 len = 0;
589 }
590 if (len) {
591 uint i;
592 for (i = 0; i < len; i++) {
593 uint32 ch = *bp++;
594 if (ch > 0xff)
595 ch = '?';
596 *buf++ = (char)ch;
597 }
598 if (bp > (uint32 *)_bufEof)
599 _bufEof = bp;
600 }
601
602 _readCount += len;
603 _bufPtr = bp;
604 }
605 }
606
607 return len;
608 }
609
getBufferUni(uint32 * buf,uint len)610 uint MemoryStream::getBufferUni(uint32 *buf, uint len) {
611 if (!_readable)
612 return 0;
613
614 if (_bufPtr >= _bufEnd) {
615 len = 0;
616 } else {
617 if (!_unicode) {
618 unsigned char *bp = (unsigned char *)_bufPtr;
619 if (bp + len > (unsigned char *)_bufEnd) {
620 uint lx;
621 lx = (bp + len) - (unsigned char *)_bufEnd;
622 if (lx < len)
623 len -= lx;
624 else
625 len = 0;
626 }
627 if (len) {
628 uint i;
629 for (i = 0; i < len; i++)
630 buf[i] = bp[i];
631 bp += len;
632 if (bp > (unsigned char *)_bufEof)
633 _bufEof = bp;
634 }
635 _readCount += len;
636 _bufPtr = bp;
637 } else {
638 uint32 *bp = (uint32 *)_bufPtr;
639 if (bp + len > (uint32 *)_bufEnd) {
640 uint lx;
641 lx = (bp + len) - (uint32 *)_bufEnd;
642 if (lx < len)
643 len -= lx;
644 else
645 len = 0;
646 }
647 if (len) {
648 memcpy(buf, bp, len * 4);
649 bp += len;
650 if (bp > (uint32 *)_bufEof)
651 _bufEof = bp;
652 }
653 _readCount += len;
654 _bufPtr = bp;
655 }
656 }
657
658 return len;
659 }
660
getLine(char * buf,uint len)661 uint MemoryStream::getLine(char *buf, uint len) {
662 uint lx;
663 bool gotNewline;
664
665 if (len == 0)
666 return 0;
667
668 len -= 1; // for the terminal null
669 if (!_unicode) {
670 if (_bufPtr >= _bufEnd) {
671 len = 0;
672 } else {
673 if ((char *)_bufPtr + len > (char *)_bufEnd) {
674 lx = ((char *)_bufPtr + len) - (char *)_bufEnd;
675 if (lx < len)
676 len -= lx;
677 else
678 len = 0;
679 }
680 }
681
682 gotNewline = false;
683 for (lx = 0; lx < len && !gotNewline; lx++) {
684 buf[lx] = ((char *)_bufPtr)[lx];
685 gotNewline = (buf[lx] == '\n');
686 }
687
688 buf[lx] = '\0';
689 _bufPtr = ((char *)_bufPtr) + lx;
690 } else {
691 if (_bufPtr >= _bufEnd) {
692 len = 0;
693 } else {
694 if ((char *)_bufPtr + len > (char *)_bufEnd) {
695 lx = ((char *)_bufPtr + len) - (char *)_bufEnd;
696 if (lx < len)
697 len -= lx;
698 else
699 len = 0;
700 }
701 }
702
703 gotNewline = false;
704 for (lx = 0; lx < len && !gotNewline; lx++) {
705 uint32 ch;
706 ch = ((uint32 *)_bufPtr)[lx];
707 if (ch >= 0x100)
708 ch = '?';
709 buf[lx] = (char)ch;
710 gotNewline = (ch == '\n');
711 }
712
713 buf[lx] = '\0';
714 _bufPtr = ((uint32 *)_bufPtr) + lx;
715 }
716
717 _readCount += lx;
718 return lx;
719 }
720
getLineUni(uint32 * ubuf,uint len)721 uint MemoryStream::getLineUni(uint32 *ubuf, uint len) {
722 bool gotNewline;
723 int lx;
724
725 if (!_readable || len == 0)
726 return 0;
727
728 len -= 1; // for the terminal null
729 if (!_unicode) {
730 if (_bufPtr >= _bufEnd) {
731 len = 0;
732 } else {
733 if ((char *)_bufPtr + len > (char *)_bufEnd) {
734 lx = ((char *)_bufPtr + len) - (char *)_bufEnd;
735 if (lx < (int)len)
736 len -= lx;
737 else
738 len = 0;
739 }
740 }
741 gotNewline = false;
742 for (lx = 0; lx < (int)len && !gotNewline; lx++) {
743 ubuf[lx] = ((unsigned char *)_bufPtr)[lx];
744 gotNewline = (ubuf[lx] == '\n');
745 }
746 ubuf[lx] = '\0';
747 _bufPtr = ((unsigned char *)_bufPtr) + lx;
748 } else {
749 if (_bufPtr >= _bufEnd) {
750 len = 0;
751 } else {
752 if ((uint32 *)_bufPtr + len > (uint32 *)_bufEnd) {
753 lx = ((uint32 *)_bufPtr + len) - (uint32 *)_bufEnd;
754 if (lx < (int)len)
755 len -= lx;
756 else
757 len = 0;
758 }
759 }
760 gotNewline = false;
761 for (lx = 0; lx < (int)len && !gotNewline; lx++) {
762 uint32 ch;
763 ch = ((uint32 *)_bufPtr)[lx];
764 ubuf[lx] = ch;
765 gotNewline = (ch == '\n');
766 }
767 ubuf[lx] = '\0';
768 _bufPtr = ((uint32 *)_bufPtr) + lx;
769 }
770
771 _readCount += lx;
772 return lx;
773 }
774
775 /*--------------------------------------------------------------------------*/
776
ensureOp(FileMode mode)777 void IOStream::ensureOp(FileMode mode) {
778 // No implementation
779 }
780
putChar(unsigned char ch)781 void IOStream::putChar(unsigned char ch) {
782 if (!_writable)
783 return;
784 ++_writeCount;
785
786 ensureOp(filemode_Write);
787 if (!_unicode) {
788 _outStream->writeByte(ch);
789 } else if (_textFile) {
790 putCharUtf8((uint)ch);
791 } else {
792 _outStream->writeUint32BE(ch);
793 }
794
795 _outStream->flush();
796 }
797
putCharUni(uint32 ch)798 void IOStream::putCharUni(uint32 ch) {
799 if (!_writable)
800 return;
801 ++_writeCount;
802
803 ensureOp(filemode_Write);
804 if (!_unicode) {
805 if (ch >= 0x100)
806 ch = '?';
807 _outStream->writeByte(ch);
808 } else if (_textFile) {
809 putCharUtf8(ch);
810 } else {
811 _outStream->writeUint32BE(ch);
812 }
813
814 _outStream->flush();
815 }
816
putBuffer(const char * buf,size_t len)817 void IOStream::putBuffer(const char *buf, size_t len) {
818 if (!_writable)
819 return;
820 _writeCount += len;
821
822 ensureOp(filemode_Write);
823 for (size_t lx = 0; lx < len; lx++) {
824 unsigned char ch = ((const unsigned char *)buf)[lx];
825 if (!_unicode) {
826 _outStream->writeByte(ch);
827 } else if (_textFile) {
828 putCharUtf8((uint)ch);
829 } else {
830 _outStream->writeUint32BE(ch);
831 }
832 }
833
834 _outStream->flush();
835 }
836
putBufferUni(const uint32 * buf,size_t len)837 void IOStream::putBufferUni(const uint32 *buf, size_t len) {
838 if (!_writable)
839 return;
840 _writeCount += len;
841
842
843 ensureOp(filemode_Write);
844 for (size_t lx = 0; lx < len; lx++) {
845 uint32 ch = buf[lx];
846 if (!_unicode) {
847 if (ch >= 0x100)
848 ch = '?';
849 _outStream->writeByte(ch);
850 } else if (_textFile) {
851 putCharUtf8(ch);
852 } else {
853 _outStream->writeUint32BE(ch);
854 }
855 }
856
857 _outStream->flush();
858 }
859
putCharUtf8(uint val)860 void IOStream::putCharUtf8(uint val) {
861 if (val < 0x80) {
862 _outStream->writeByte(val);
863 } else if (val < 0x800) {
864 _outStream->writeByte((0xC0 | ((val & 0x7C0) >> 6)));
865 _outStream->writeByte((0x80 | (val & 0x03F)));
866 } else if (val < 0x10000) {
867 _outStream->writeByte((0xE0 | ((val & 0xF000) >> 12)));
868 _outStream->writeByte((0x80 | ((val & 0x0FC0) >> 6)));
869 _outStream->writeByte((0x80 | (val & 0x003F)));
870 } else if (val < 0x200000) {
871 _outStream->writeByte((0xF0 | ((val & 0x1C0000) >> 18)));
872 _outStream->writeByte((0x80 | ((val & 0x03F000) >> 12)));
873 _outStream->writeByte((0x80 | ((val & 0x000FC0) >> 6)));
874 _outStream->writeByte((0x80 | (val & 0x00003F)));
875 } else {
876 _outStream->writeByte('?');
877 }
878 }
879
getCharUtf8()880 int IOStream::getCharUtf8() {
881 uint res;
882 uint val0, val1, val2, val3;
883
884 if (_inStream->eos())
885 return -1;
886 val0 = _inStream->readByte();
887 if (val0 < 0x80) {
888 res = val0;
889 return res;
890 }
891
892 if ((val0 & 0xe0) == 0xc0) {
893 if (_inStream->eos()) {
894 warning("incomplete two-byte character");
895 return -1;
896 }
897
898 val1 = _inStream->readByte();
899 if ((val1 & 0xc0) != 0x80) {
900 warning("malformed two-byte character");
901 return '?';
902 }
903
904 res = (val0 & 0x1f) << 6;
905 res |= (val1 & 0x3f);
906 return res;
907 }
908
909 if ((val0 & 0xf0) == 0xe0) {
910 val1 = _inStream->readByte();
911 val2 = _inStream->readByte();
912 if (_inStream->eos()) {
913 warning("incomplete three-byte character");
914 return -1;
915 }
916 if ((val1 & 0xc0) != 0x80) {
917 warning("malformed three-byte character");
918 return '?';
919 }
920 if ((val2 & 0xc0) != 0x80) {
921 warning("malformed three-byte character");
922 return '?';
923 }
924
925 res = (((val0 & 0xf) << 12) & 0x0000f000);
926 res |= (((val1 & 0x3f) << 6) & 0x00000fc0);
927 res |= (((val2 & 0x3f)) & 0x0000003f);
928 return res;
929 }
930
931 if ((val0 & 0xf0) == 0xf0) {
932 if ((val0 & 0xf8) != 0xf0) {
933 warning("malformed four-byte character");
934 return '?';
935 }
936
937 val1 = _inStream->readByte();
938 val2 = _inStream->readByte();
939 val3 = _inStream->readByte();
940 if (_inStream->eos()) {
941 warning("incomplete four-byte character");
942 return -1;
943 }
944 if ((val1 & 0xc0) != 0x80) {
945 warning("malformed four-byte character");
946 return '?';
947 }
948 if ((val2 & 0xc0) != 0x80) {
949 warning("malformed four-byte character");
950 return '?';
951 }
952 if ((val3 & 0xc0) != 0x80) {
953 warning("malformed four-byte character");
954 return '?';
955 }
956
957 res = (((val0 & 0x7) << 18) & 0x1c0000);
958 res |= (((val1 & 0x3f) << 12) & 0x03f000);
959 res |= (((val2 & 0x3f) << 6) & 0x000fc0);
960 res |= (((val3 & 0x3f)) & 0x00003f);
961 return res;
962 }
963
964 warning("malformed character");
965 return '?';
966 }
967
getPosition() const968 uint IOStream::getPosition() const {
969 return _outStream ? _outStream->pos() : _inStream->pos();
970 }
971
setPosition(int pos,uint seekMode)972 void IOStream::setPosition(int pos, uint seekMode) {
973 _lastOp = 0;
974 if (_unicode)
975 pos *= 4;
976
977 if (_inStream) {
978 _inStream->seek(pos, SEEK_SET);
979 } else {
980 Common::SeekableWriteStream *ws =
981 dynamic_cast<Common::SeekableWriteStream *>(_outStream);
982
983 if (ws)
984 ws->seek(pos, SEEK_SET);
985 else
986 error("seek not supported for writing files");
987 }
988 }
989
getChar()990 int IOStream::getChar() {
991 if (!_readable)
992 return -1;
993
994 ensureOp(filemode_Read);
995 int res;
996 if (!_unicode) {
997 res = _inStream->eos() ? -1 : _inStream->readByte();
998 } else if (_textFile) {
999 res = getCharUtf8();
1000 } else {
1001 uint32 ch;
1002 res = _inStream->readByte();
1003 if (_inStream->eos())
1004 return -1;
1005 ch = (res & 0xFF);
1006 res = _inStream->readByte();
1007 if (_inStream->eos())
1008 return -1;
1009 ch = (ch << 8) | (res & 0xFF);
1010 res = _inStream->readByte();
1011 if (_inStream->eos())
1012 return -1;
1013 ch = (ch << 8) | (res & 0xFF);
1014 res = _inStream->readByte();
1015 if (_inStream->eos())
1016 return -1;
1017 ch = (ch << 8) | (res & 0xFF);
1018 res = ch;
1019 }
1020 if (res != -1) {
1021 _readCount++;
1022 if (res >= 0x100)
1023 return '?';
1024 return (int)res;
1025 } else {
1026 return -1;
1027 }
1028 }
1029
getCharUni()1030 int IOStream::getCharUni() {
1031 if (!_readable)
1032 return -1;
1033
1034 ensureOp(filemode_Read);
1035 int res;
1036 if (!_unicode) {
1037 res = _inStream->readByte();
1038 } else if (_textFile) {
1039 res = getCharUtf8();
1040 } else {
1041 uint32 ch;
1042 res = _inStream->readByte();
1043 if (res == -1)
1044 return -1;
1045 ch = (res & 0xFF);
1046 res = _inStream->readByte();
1047 if (res == -1)
1048 return -1;
1049 ch = (ch << 8) | (res & 0xFF);
1050 res = _inStream->readByte();
1051 if (res == -1)
1052 return -1;
1053 ch = (ch << 8) | (res & 0xFF);
1054 res = _inStream->readByte();
1055 if (res == -1)
1056 return -1;
1057 ch = (ch << 8) | (res & 0xFF);
1058 res = ch;
1059 }
1060 if (res != -1) {
1061 _readCount++;
1062 return (int)res;
1063 } else {
1064 return -1;
1065 }
1066 }
1067
getBuffer(char * buf,uint len)1068 uint IOStream::getBuffer(char *buf, uint len) {
1069 ensureOp(filemode_Read);
1070 if (!_unicode) {
1071 uint res;
1072 res = _inStream->read(buf, len);
1073 _readCount += res;
1074 return res;
1075 } else if (_textFile) {
1076 uint lx;
1077 for (lx = 0; lx < len; lx++) {
1078 uint32 ch;
1079 ch = getCharUtf8();
1080 if (ch == (uint)-1)
1081 break;
1082 _readCount++;
1083 if (ch >= 0x100)
1084 ch = '?';
1085 buf[lx] = (char)ch;
1086 }
1087 return lx;
1088 } else {
1089 uint lx;
1090 for (lx = 0; lx < len; lx++) {
1091 int res;
1092 uint32 ch;
1093 res = _inStream->readByte();
1094 if (res == -1)
1095 break;
1096 ch = (res & 0xFF);
1097 res = _inStream->readByte();
1098 if (res == -1)
1099 break;
1100 ch = (ch << 8) | (res & 0xFF);
1101 res = _inStream->readByte();
1102 if (res == -1)
1103 break;
1104 ch = (ch << 8) | (res & 0xFF);
1105 res = _inStream->readByte();
1106 if (res == -1)
1107 break;
1108 ch = (ch << 8) | (res & 0xFF);
1109 _readCount++;
1110 if (ch >= 0x100)
1111 ch = '?';
1112 buf[lx] = (char)ch;
1113 }
1114 return lx;
1115 }
1116 }
1117
getBufferUni(uint32 * buf,uint len)1118 uint IOStream::getBufferUni(uint32 *buf, uint len) {
1119 if (!_readable)
1120 return 0;
1121
1122 ensureOp(filemode_Read);
1123 if (!_unicode) {
1124 uint lx;
1125 for (lx = 0; lx < len; lx++) {
1126 int res;
1127 uint32 ch;
1128 res = _inStream->readByte();
1129 if (res == -1)
1130 break;
1131 ch = (res & 0xFF);
1132 _readCount++;
1133 buf[lx] = ch;
1134 }
1135 return lx;
1136 } else if (_textFile) {
1137 uint lx;
1138 for (lx = 0; lx < len; lx++) {
1139 uint32 ch;
1140 ch = getCharUtf8();
1141 if (ch == (uint)-1)
1142 break;
1143 _readCount++;
1144 buf[lx] = ch;
1145 }
1146 return lx;
1147 } else {
1148 uint lx;
1149 for (lx = 0; lx < len; lx++) {
1150 int res;
1151 uint32 ch;
1152 res = _inStream->readByte();
1153 if (res == -1)
1154 break;
1155 ch = (res & 0xFF);
1156 res = _inStream->readByte();
1157 if (res == -1)
1158 break;
1159 ch = (ch << 8) | (res & 0xFF);
1160 res = _inStream->readByte();
1161 if (res == -1)
1162 break;
1163 ch = (ch << 8) | (res & 0xFF);
1164 res = _inStream->readByte();
1165 if (res == -1)
1166 break;
1167 ch = (ch << 8) | (res & 0xFF);
1168 _readCount++;
1169 buf[lx] = ch;
1170 }
1171 return lx;
1172 }
1173 }
1174
getLine(char * buf,uint len)1175 uint IOStream::getLine(char *buf, uint len) {
1176 uint lx;
1177 bool gotNewline;
1178
1179 if (len == 0)
1180 return 0;
1181
1182 ensureOp(filemode_Read);
1183 if (!_unicode) {
1184 char *res = buf;
1185 for (; len > 0; ++res, --len) {
1186 *res = _inStream->readByte();
1187 if (*res == '\n')
1188 break;
1189 }
1190 *res = '\0';
1191
1192 lx = strlen(buf);
1193 _readCount += lx;
1194 return lx;
1195 } else if (_textFile) {
1196 len -= 1; // for the terminal null
1197 gotNewline = false;
1198 for (lx = 0; lx < len && !gotNewline; lx++) {
1199 uint32 ch;
1200 ch = getCharUtf8();
1201 if (ch == (uint)-1)
1202 break;
1203 _readCount++;
1204 if (ch >= 0x100)
1205 ch = '?';
1206 buf[lx] = (char)ch;
1207 gotNewline = (ch == '\n');
1208 }
1209 buf[lx] = '\0';
1210 return lx;
1211 } else {
1212 len -= 1; // for the terminal null
1213 gotNewline = false;
1214 for (lx = 0; lx < len && !gotNewline; lx++) {
1215 int res;
1216 uint32 ch;
1217 res = _inStream->readByte();
1218 if (res == -1)
1219 break;
1220 ch = (res & 0xFF);
1221 res = _inStream->readByte();
1222 if (res == -1)
1223 break;
1224 ch = (ch << 8) | (res & 0xFF);
1225 res = _inStream->readByte();
1226 if (res == -1)
1227 break;
1228 ch = (ch << 8) | (res & 0xFF);
1229 res = _inStream->readByte();
1230 if (res == -1)
1231 break;
1232 ch = (ch << 8) | (res & 0xFF);
1233 _readCount++;
1234 if (ch >= 0x100)
1235 ch = '?';
1236 buf[lx] = (char)ch;
1237 gotNewline = (ch == '\n');
1238 }
1239
1240 buf[lx] = '\0';
1241 return lx;
1242 }
1243 }
1244
getLineUni(uint32 * ubuf,uint len)1245 uint IOStream::getLineUni(uint32 *ubuf, uint len) {
1246 bool gotNewline;
1247 int lx;
1248
1249 if (!_readable || len == 0)
1250 return 0;
1251
1252 ensureOp(filemode_Read);
1253 if (!_unicode) {
1254 len -= 1; // for the terminal null
1255 gotNewline = false;
1256 for (lx = 0; lx < (int)len && !gotNewline; lx++) {
1257 int res;
1258 uint32 ch;
1259 res = _inStream->readByte();
1260 if (res == -1)
1261 break;
1262 ch = (res & 0xFF);
1263 _readCount++;
1264 ubuf[lx] = ch;
1265 gotNewline = (ch == '\n');
1266 }
1267 ubuf[lx] = '\0';
1268 return lx;
1269 } else if (_textFile) {
1270 len -= 1; // for the terminal null
1271 gotNewline = false;
1272 for (lx = 0; lx < (int)len && !gotNewline; lx++) {
1273 uint32 ch;
1274 ch = getCharUtf8();
1275 if (ch == (uint)-1)
1276 break;
1277 _readCount++;
1278 ubuf[lx] = ch;
1279 gotNewline = (ch == '\n');
1280 }
1281 ubuf[lx] = '\0';
1282 return lx;
1283 } else {
1284 len -= 1; // for the terminal null
1285 gotNewline = false;
1286 for (lx = 0; lx < (int)len && !gotNewline; lx++) {
1287 int res;
1288 uint32 ch;
1289 res = _inStream->readByte();
1290 if (res == -1)
1291 break;
1292 ch = (res & 0xFF);
1293 res = _inStream->readByte();
1294 if (res == -1)
1295 break;
1296 ch = (ch << 8) | (res & 0xFF);
1297 res = _inStream->readByte();
1298 if (res == -1)
1299 break;
1300 ch = (ch << 8) | (res & 0xFF);
1301 res = _inStream->readByte();
1302 if (res == -1)
1303 break;
1304 ch = (ch << 8) | (res & 0xFF);
1305 _readCount++;
1306 ubuf[lx] = ch;
1307 gotNewline = (ch == '\n');
1308 }
1309 ubuf[lx] = '\0';
1310 return lx;
1311 }
1312 }
1313
1314 /*--------------------------------------------------------------------------*/
1315
FileStream(Streams * streams,frefid_t fref,uint fmode,uint rock,bool unicode)1316 FileStream::FileStream(Streams *streams, frefid_t fref, uint fmode, uint rock, bool unicode) :
1317 IOStream(streams, fmode == filemode_Read, fmode != filemode_Read, rock, unicode),
1318 _inSave(nullptr), _outSave(nullptr) {
1319
1320 _textFile = fref->_textMode;
1321 Common::String fname = fref->_slotNumber == -1 ? fref->_filename : fref->getSaveName();
1322
1323 if (fmode == filemode_Write || fmode == filemode_ReadWrite || fmode == filemode_WriteAppend) {
1324 _outSave = g_system->getSavefileManager()->openForSaving(fname, false);
1325 if (!_outSave)
1326 error("Could open file for writing - %s", fname.c_str());
1327 setStream(_outSave);
1328
1329 } else if (fmode == filemode_Read) {
1330 if (_file.open(fname)) {
1331 setStream(&_file);
1332 } else {
1333 _inSave = g_system->getSavefileManager()->openForLoading(fname);
1334 setStream(_inSave);
1335
1336 if (!_inSave)
1337 error("Could not open for reading - %s", fname.c_str());
1338 }
1339 }
1340 }
1341
~FileStream()1342 FileStream::~FileStream() {
1343 _file.close();
1344 delete _inSave;
1345 if (_outSave) {
1346 _outSave->finalize();
1347 delete _outSave;
1348 }
1349 }
1350
1351 /*--------------------------------------------------------------------------*/
1352
Streams()1353 Streams::Streams() : _streamList(nullptr), _currentStream(nullptr) {
1354 }
1355
~Streams()1356 Streams::~Streams() {
1357 for (Stream *currStream = _streamList, *nextStream; currStream; currStream = nextStream) {
1358 nextStream = currStream->_next;
1359 delete currStream;
1360 }
1361 }
1362
openFileStream(frefid_t fref,uint fmode,uint rock,bool unicode)1363 FileStream *Streams::openFileStream(frefid_t fref, uint fmode, uint rock, bool unicode) {
1364 FileStream *stream = new FileStream(this, fref, fmode, rock, unicode);
1365 addStream(stream);
1366 return stream;
1367 }
1368
openStream(Common::SeekableReadStream * rs,uint rock)1369 IOStream *Streams::openStream(Common::SeekableReadStream *rs, uint rock) {
1370 IOStream *stream = new IOStream(this, rs, rock);
1371 addStream(stream);
1372 return stream;
1373 }
1374
openStream(Common::WriteStream * ws,uint rock)1375 IOStream *Streams::openStream(Common::WriteStream *ws, uint rock) {
1376 IOStream *stream = new IOStream(this, ws, rock);
1377 addStream(stream);
1378 return stream;
1379 }
1380
openWindowStream(Window * window)1381 WindowStream *Streams::openWindowStream(Window *window) {
1382 WindowStream *stream = new WindowStream(this, window);
1383 addStream(stream);
1384 return stream;
1385 }
1386
openMemoryStream(void * buf,size_t buflen,FileMode mode,uint rock,bool unicode)1387 MemoryStream *Streams::openMemoryStream(void *buf, size_t buflen, FileMode mode, uint rock, bool unicode) {
1388 MemoryStream *stream = new MemoryStream(this, buf, buflen, mode, rock, unicode);
1389 addStream(stream);
1390 return stream;
1391 }
1392
addStream(Stream * stream)1393 void Streams::addStream(Stream *stream) {
1394 stream->_next = _streamList;
1395 _streamList = stream;
1396 if (stream->_next)
1397 stream->_next->_prev = stream;
1398 }
1399
removeStream(Stream * stream)1400 void Streams::removeStream(Stream *stream) {
1401 Stream *prev = stream->_prev;
1402 Stream *next = stream->_next;
1403
1404 if (prev)
1405 prev->_next = next;
1406 else
1407 _streamList = next;
1408 if (next)
1409 next->_prev = prev;
1410
1411 // Remove the stream as the echo stream of any window
1412 for (Windows::iterator i = g_vm->_windows->begin(); i != g_vm->_windows->end(); ++i) {
1413 if ((*i)->_echoStream == stream)
1414 (*i)->_echoStream = nullptr;
1415 }
1416
1417 if (_currentStream == stream)
1418 _currentStream = nullptr;
1419 }
1420
getFirst(uint * rock)1421 Stream *Streams::getFirst(uint *rock) {
1422 if (rock)
1423 *rock = _streamList ? _streamList->_rock : 0;
1424 return _streamList;
1425 }
1426
1427
createByPrompt(uint usage,FileMode fmode,uint rock)1428 frefid_t Streams::createByPrompt(uint usage, FileMode fmode, uint rock) {
1429 switch (usage & fileusage_TypeMask) {
1430 case fileusage_SavedGame: {
1431 if (fmode == filemode_Write) {
1432 // Select a savegame slot
1433 GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
1434
1435 int slot = dialog->runModalWithCurrentTarget();
1436 if (slot >= 0) {
1437 Common::String desc = dialog->getResultString();
1438 return createRef(slot, desc, usage, rock);
1439 }
1440 } else if (fmode == filemode_Read) {
1441 // Load a savegame slot
1442 GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
1443
1444 int slot = dialog->runModalWithCurrentTarget();
1445 if (slot >= 0) {
1446 return createRef(slot, "", usage, rock);
1447 }
1448 } else {
1449 error("Unsupport file mode");
1450 }
1451 break;
1452 }
1453
1454 case fileusage_Transcript:
1455 return createRef("transcript.txt", fmode, rock);
1456
1457 default:
1458 error("Unsupport file mode");
1459 break;
1460 }
1461
1462 return nullptr;
1463 }
1464
createRef(int slot,const Common::String & desc,uint usage,uint rock)1465 frefid_t Streams::createRef(int slot, const Common::String &desc, uint usage, uint rock) {
1466 frefid_t fref = new FileReference();
1467 fref->_slotNumber = slot;
1468 fref->_description = desc;
1469 fref->_textMode = ((usage & fileusage_TextMode) != 0);
1470 fref->_fileType = (FileUsage)(usage & fileusage_TypeMask);
1471
1472 _fileReferences.push_back(FileRefArray::value_type(fref));
1473 return fref;
1474 }
1475
createRef(const Common::String & filename,uint usage,uint rock)1476 frefid_t Streams::createRef(const Common::String &filename, uint usage, uint rock) {
1477 frefid_t fref = new FileReference();
1478 fref->_filename = filename;
1479 fref->_textMode = ((usage & fileusage_TextMode) != 0);
1480 fref->_fileType = (FileUsage)(usage & fileusage_TypeMask);
1481
1482 _fileReferences.push_back(FileRefArray::value_type(fref));
1483 return fref;
1484 }
1485
createTemp(uint usage,uint rock)1486 frefid_t Streams::createTemp(uint usage, uint rock) {
1487 return createRef(Common::String::format("%s.tmp", g_vm->getTargetName().c_str()),
1488 usage, rock);
1489 }
1490
createFromRef(frefid_t fref,uint usage,uint rock)1491 frefid_t Streams::createFromRef(frefid_t fref, uint usage, uint rock) {
1492 return createRef(fref->_filename, usage, rock);
1493 }
1494
deleteRef(frefid_t fref)1495 void Streams::deleteRef(frefid_t fref) {
1496 for (uint idx = 0; idx < _fileReferences.size(); ++idx) {
1497 if (_fileReferences[idx].get() == fref) {
1498 _fileReferences.remove_at(idx);
1499 return;
1500 }
1501 }
1502 }
1503
iterate(frefid_t fref,uint * rock)1504 frefid_t Streams::iterate(frefid_t fref, uint *rock) {
1505 // Find reference following the specified one
1506 int index = -1;
1507 for (uint idx = 0; idx < _fileReferences.size(); ++idx) {
1508 if (fref == nullptr || _fileReferences[idx].get() == fref) {
1509 if (idx < (_fileReferences.size() - 1))
1510 index = idx + 1;
1511 break;
1512 }
1513 }
1514
1515 if (index != -1) {
1516 if (rock)
1517 *rock = _fileReferences[index].get()->_rock;
1518 return _fileReferences[index].get();
1519 }
1520
1521 if (rock)
1522 *rock = 0;
1523 return nullptr;
1524 }
1525
1526 /*--------------------------------------------------------------------------*/
1527
FileReference()1528 FileReference::FileReference() : _rock(0), _slotNumber(-1), _fileType(fileusage_Data), _textMode(false) {
1529 if (g_vm->gli_register_obj)
1530 _dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Fileref);
1531 }
1532
FileReference(int slot,const Common::String & desc,uint usage,uint rock)1533 FileReference::FileReference(int slot, const Common::String &desc, uint usage, uint rock) :
1534 _rock(rock), _slotNumber(slot), _description(desc),
1535 _fileType((FileUsage)(usage & fileusage_TypeMask)), _textMode(usage & fileusage_TextMode) {
1536 if (g_vm->gli_register_obj)
1537 _dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Fileref);
1538 }
1539
~FileReference()1540 FileReference::~FileReference() {
1541 if (g_vm->gli_unregister_obj)
1542 (*g_vm->gli_unregister_obj)(this, gidisp_Class_Fileref, _dispRock);
1543 }
1544
getSaveName() const1545 const Common::String FileReference::getSaveName() const {
1546 assert(_slotNumber != -1);
1547 return g_vm->getSaveName(_slotNumber);
1548 }
1549
exists() const1550 bool FileReference::exists() const {
1551 Common::String filename;
1552
1553 if (_slotNumber == -1) {
1554 if (Common::File::exists(_filename))
1555 return true;
1556 filename = _filename;
1557 } else {
1558 filename = getSaveName();
1559 }
1560
1561 // Check for a savegame (or other file in the save folder) with that name
1562 Common::InSaveFile *inSave = g_system->getSavefileManager()->openForLoading(filename);
1563 bool result = inSave != nullptr;
1564 delete inSave;
1565 return result;
1566 }
1567
deleteFile()1568 void FileReference::deleteFile() {
1569 Common::String filename = (_slotNumber == -1) ? _filename : getSaveName();
1570 g_system->getSavefileManager()->removeSavefile(filename);
1571 }
1572
1573 } // End of namespace Glk
1574