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 #ifndef GLK_STREAMS_H
24 #define GLK_STREAMS_H
25 
26 #include "common/scummsys.h"
27 #include "common/file.h"
28 #include "common/savefile.h"
29 #include "common/str.h"
30 #include "glk/glk_types.h"
31 
32 namespace Glk {
33 
34 #define SAVEGAME_VERSION 1
35 
36 class Window;
37 class Streams;
38 
39 enum FileUsage {
40 	fileusage_Data = 0x00,
41 	fileusage_SavedGame = 0x01,
42 	fileusage_Transcript = 0x02,
43 	fileusage_InputRecord = 0x03,
44 	fileusage_TypeMask = 0x0f,
45 
46 	fileusage_TextMode = 0x100,
47 	fileusage_BinaryMode = 0x000
48 };
49 
50 enum FileMode {
51 	filemode_Write = 0x01,
52 	filemode_Read = 0x02,
53 	filemode_ReadWrite = 0x03,
54 	filemode_WriteAppend = 0x05
55 };
56 
57 enum SeekMode {
58 	seekmode_Start = 0,
59 	seekmode_Current = 1,
60 	seekmode_End = 2
61 };
62 
63 struct StreamResult {
64 	uint _readCount;
65 	uint _writeCount;
66 };
67 typedef StreamResult stream_result_t;
68 
69 /**
70  * File details
71  */
72 struct FileReference {
73 	uint _rock;
74 	int _slotNumber;
75 	Common::String _description;
76 	Common::String _filename;
77 	FileUsage _fileType;
78 	bool _textMode;
79 	gidispatch_rock_t _dispRock;
80 
81 	/**
82 	 * Constructor
83 	 */
84 	FileReference();
85 
86 	/**
87 	 * Constructor
88 	 */
89 	FileReference(int slot, const Common::String &desc, uint usage, uint rock = 0);
90 
91 	/**
92 	 * Destructor
93 	 */
94 	~FileReference();
95 
96 	/**
97 	 * Get savegame filename
98 	 */
99 	const Common::String getSaveName() const;
100 
101 	/**
102 	 * Returns true if the given file exists
103 	 */
104 	bool exists() const;
105 
106 	/**
107 	 * Delete the given file
108 	 */
109 	void deleteFile();
110 };
111 
112 typedef FileReference *frefid_t;
113 typedef Common::Array< Common::SharedPtr<FileReference> > FileRefArray;
114 
115 
116 /**
117  * Base class for streams
118  */
119 class Stream {
120 public:
121 	Streams *_streams;
122 	Stream *_prev;
123 	Stream *_next;
124 	uint _rock;
125 	gidispatch_rock_t _dispRock;
126 	bool _unicode;
127 	uint _readCount;
128 	uint _writeCount;
129 	bool _readable, _writable;
130 public:
131 	/**
132 	 * Constructor
133 	 */
134 	Stream(Streams *streams, bool readable, bool writable, uint rock, bool unicode);
135 
136 	/**
137 	 * Destructor
138 	 */
139 	virtual ~Stream();
140 
141 	/**
142 	 * Get the next stream
143 	 */
144 	Stream *getNext(uint *rock) const;
145 
146 	/**
147 	 * Get the rock value for the stream
148 	 */
getRock()149 	uint getRock() const {
150 		return _rock;
151 	}
152 
153 	/**
154 	 * Fill out the total amount read and/or written
155 	 */
156 	void fillResult(StreamResult *result);
157 
158 	/**
159 	 * Close and delete the stream
160 	 */
161 	void close(StreamResult *result = nullptr);
162 
163 	/**
164 	 * Write a character
165 	 */
166 	virtual void putChar(unsigned char ch) = 0;
167 
168 	/**
169 	 * Write a unicode character
170 	 */
171 	virtual void putCharUni(uint32 ch) = 0;
172 
173 	/**
174 	 * Write a buffer
175 	 */
176 	virtual void putBuffer(const char *buf, size_t len) = 0;
177 
178 	/**
179 	 * Write a unicode character
180 	 */
181 	virtual void putBufferUni(const uint32 *buf, size_t len) = 0;
182 
183 	/**
184 	 * Remove a string from the end of the stream, if indeed it is at the end
185 	 */
unputBuffer(const char * buf,size_t len)186 	virtual void unputBuffer(const char *buf, size_t len) {}
187 
188 	/**
189 	 * Remove a string from the end of the stream, if indeed it is at the end
190 	 */
unputBufferUni(const uint32 * buf,size_t len)191 	virtual void unputBufferUni(const uint32 *buf, size_t len) {}
192 
193 	/**
194 	 * Send a line to the stream with a trailing newline
195 	 */
echoLine(const char * buf,uint len)196 	void echoLine(const char *buf, uint len) {
197 		putBuffer(buf, len);
198 		putChar('\n');
199 	};
200 
201 	/**
202 	 * Send a line to the stream with a trailing newline
203 	 */
echoLineUni(const uint32 * buf,uint len)204 	void echoLineUni(const uint32 *buf, uint len) {
205 		putBufferUni(buf, len);
206 		putCharUni('\n');
207 	}
208 
getPosition()209 	virtual uint getPosition() const {
210 		return 0;
211 	}
212 
setPosition(int pos,uint seekMode)213 	virtual void setPosition(int pos, uint seekMode) {}
214 
setStyle(uint val)215 	virtual void setStyle(uint val) {}
216 
217 	/**
218 	 * Get a character from the stream
219 	 */
getChar()220 	virtual int getChar() {
221 		return -1;
222 	}
223 
224 	/**
225 	 * Get a unicode character from the stream
226 	 */
getCharUni()227 	virtual int getCharUni() {
228 		return -1;
229 	}
230 
231 	/**
232 	 * Get a buffer
233 	 */
getBuffer(char * buf,uint len)234 	virtual uint getBuffer(char *buf, uint len) {
235 		return 0;
236 	}
237 
238 	/**
239 	 * Get a unicode buffer
240 	 */
getBufferUni(uint32 * buf,uint len)241 	virtual uint getBufferUni(uint32 *buf, uint len) {
242 		return 0;
243 	}
244 
245 	/**
246 	 * Get a line
247 	 */
getLine(char * buf,uint len)248 	virtual uint getLine(char *buf, uint len) {
249 		return 0;
250 	}
251 
252 	/**
253 	 * Get a unicode line
254 	 */
getLineUni(uint32 * ubuf,uint len)255 	virtual uint getLineUni(uint32 *ubuf, uint len) {
256 		return 0;
257 	}
258 
259 	/**
260 	 * Set a hyperlink
261 	 */
setHyperlink(uint linkVal)262 	virtual void setHyperlink(uint linkVal) {}
263 
264 	/**
265 	 * Set the style colors
266 	 */
267 	virtual void setZColors(uint fg, uint bg);
268 
269 	/**
270 	 * Set the reverse video style
271 	 */
272 	virtual void setReverseVideo(bool reverse);
273 
274 	/**
275 	 * Cast a stream to a ScummVM write stream
276 	 */
277 	virtual operator Common::WriteStream *() const { return nullptr; }
278 
279 	/**
280 	 * Cast a stream to a ScummVM read stream
281 	 */
282 	virtual operator Common::SeekableReadStream *() const { return nullptr; }
283 };
284 typedef Stream *strid_t;
285 
286 /**
287  * Implements the stream for writing text to a window
288  */
289 class WindowStream : public Stream {
290 private:
291 	Window *_window;
292 public:
293 	/**
294 	 * Constructor
295 	 */
296 	WindowStream(Streams *streams, Window *window, uint rock = 0, bool unicode = true) :
Stream(streams,false,true,rock,unicode)297 		Stream(streams, false, true, rock, unicode), _window(window) {}
298 
299 	/**
300 	 * Destructor
301 	 */
302 	~WindowStream() override;
303 
304 	/**
305 	 * Close the stream
306 	 */
307 	virtual void close(StreamResult *result = nullptr);
308 
309 	/**
310 	 * Write a character
311 	 */
312 	void putChar(unsigned char ch) override;
313 
314 	/**
315 	 * Write a unicode character
316 	 */
317 	void putCharUni(uint32 ch) override;
318 
319 	/**
320 	 * Write a buffer
321 	 */
322 	void putBuffer(const char *buf, size_t len) override;
323 
324 	/**
325 	 * Write a unicode character
326 	 */
327 	void putBufferUni(const uint32 *buf, size_t len) override;
328 
329 	/**
330 	 * Remove a string from the end of the stream, if indeed it is at the end
331 	 */
332 	void unputBuffer(const char *buf, size_t len) override;
333 
334 	/**
335 	 * Remove a string from the end of the stream, if indeed it is at the end
336 	 */
337 	void unputBufferUni(const uint32 *buf, size_t len) override;
338 
339 	void setStyle(uint val) override;
340 
341 	/**
342 	 * Set a hyperlink
343 	 */
344 	void setHyperlink(uint linkVal) override;
345 
346 	/**
347 	 * Set the style colors
348 	 */
349 	void setZColors(uint fg, uint bg) override;
350 
351 	/**
352 	 * Set the reverse video style
353 	 */
354 	void setReverseVideo(bool reverse) override;
355 };
356 
357 /**
358  * Implements an in-memory stream
359  */
360 class MemoryStream : public Stream {
361 private:
362 	void *_buf;     ///< unsigned char* for latin1, uint* for unicode
363 	void *_bufPtr;
364 	void *_bufEnd;
365 	void *_bufEof;
366 	size_t _bufLen; ///< # of bytes for latin1, # of 4-byte words for unicode
367 	gidispatch_rock_t _arrayRock;
368 public:
369 	/**
370 	 * Constructor
371 	 */
372 	MemoryStream(Streams *streams, void *buf, size_t buflen, FileMode mode, uint rock = 0, bool unicode = true);
373 
374 	/**
375 	 * Destructor
376 	 */
377 	~MemoryStream() override;
378 
379 	/**
380 	 * Write a character
381 	 */
382 	void putChar(unsigned char ch) override;
383 
384 	/**
385 	 * Write a unicode character
386 	 */
387 	void putCharUni(uint32 ch) override;
388 
389 	/**
390 	 * Write a buffer
391 	 */
392 	void putBuffer(const char *buf, size_t len) override;
393 
394 	/**
395 	 * Write a unicode character
396 	 */
397 	void putBufferUni(const uint32 *buf, size_t len) override;
398 
399 	uint getPosition() const override;
400 
401 	void setPosition(int pos, uint seekMode) override;
402 
403 	/**
404 	 * Get a character from the stream
405 	 */
406 	int getChar() override;
407 
408 	/**
409 	 * Get a unicode character from the stream
410 	 */
411 	int getCharUni() override;
412 
413 	/**
414 	 * Get a buffer
415 	 */
416 	uint getBuffer(char *buf, uint len) override;
417 
418 	/**
419 	 * Get a unicode buffer
420 	 */
421 	uint getBufferUni(uint32 *buf, uint len) override;
422 
423 	/**
424 	 * Get a line
425 	 */
426 	uint getLine(char *buf, uint len) override;
427 
428 	/**
429 	 * Get a unicode line
430 	 */
431 	uint getLineUni(uint32 *ubuf, uint len) override;
432 };
433 
434 /**
435  * Base class for I/O streams
436  */
437 class IOStream : public Stream {
438 private:
439 	Common::SeekableReadStream *_inStream;
440 	Common::WriteStream *_outStream;
441 	uint _lastOp;                 ///< 0, filemode_Write, or filemode_Read
442 private:
443 	/**
444 	 * Ensure the stream is ready for the given operation
445 	 */
446 	void ensureOp(FileMode mode);
447 
448 	/**
449 	 * Put a UTF8 character
450 	 */
451 	void putCharUtf8(uint val);
452 
453 	/**
454 	 * Get a UTF8 character
455 	 */
456 	int getCharUtf8();
457 protected:
458 	bool _textFile;
459 public:
460 	/**
461 	 * Constructor
462 	 */
IOStream(Streams * streams,bool readable,bool writable,uint rock,bool unicode)463 	IOStream(Streams *streams, bool readable, bool writable, uint rock, bool unicode) :
464 		Stream(streams, readable, writable, rock, unicode) {}
Stream(streams,false,false,rock,false)465 	IOStream(Streams *streams, uint rock = 0) : Stream(streams, false, false, rock, false),
466 		_inStream(nullptr), _outStream(nullptr), _lastOp(0), _textFile(false) {}
467 	IOStream(Streams *streams, Common::SeekableReadStream *inStream, uint rock = 0) :
Stream(streams,true,false,rock,false)468 		Stream(streams, true, false, rock, false), _inStream(inStream), _outStream(nullptr), _lastOp(0), _textFile(false) {}
469 	IOStream(Streams *streams, Common::WriteStream *outStream, uint rock = 0) :
Stream(streams,false,true,rock,false)470 		Stream(streams, false, true, rock, false), _inStream(nullptr), _outStream(outStream), _lastOp(0), _textFile(false) {}
471 
472 	/**
473 	 * Sets the stream to use
474 	 */
setStream(Common::SeekableReadStream * rs)475 	void setStream(Common::SeekableReadStream *rs) {
476 		_inStream = rs;
477 		_outStream = nullptr;
478 		_readable = true;
479 		_writable = false;
480 	}
481 
482 	/**
483 	 * Sets the stream to use
484 	 */
setStream(Common::WriteStream * ws)485 	void setStream(Common::WriteStream *ws) {
486 		_inStream = nullptr;
487 		_outStream = ws;
488 		_readable = false;
489 		_writable = true;
490 	}
491 
492 	/**
493 	 * Write a character
494 	 */
495 	void putChar(unsigned char ch) override;
496 
497 	/**
498 	 * Write a unicode character
499 	 */
500 	void putCharUni(uint32 ch) override;
501 
502 	/**
503 	 * Write a buffer
504 	 */
505 	void putBuffer(const char *buf, size_t len) override;
506 
507 	/**
508 	 * Write a unicode character
509 	 */
510 	void putBufferUni(const uint32 *buf, size_t len) override;
511 
512 	uint getPosition() const override;
513 
514 	void setPosition(int pos, uint seekMode) override;
515 
516 	/**
517 	 * Get a character from the stream
518 	 */
519 	int getChar() override;
520 
521 	/**
522 	 * Get a unicode character from the stream
523 	 */
524 	int getCharUni() override;
525 
526 	/**
527 	 * Get a buffer
528 	 */
529 	uint getBuffer(char *buf, uint len) override;
530 
531 	/**
532 	 * Get a unicode buffer
533 	 */
534 	uint getBufferUni(uint32 *buf, uint len) override;
535 
536 	/**
537 	 * Get a line
538 	 */
539 	uint getLine(char *buf, uint len) override;
540 
541 	/**
542 	 * Get a unicode line
543 	 */
544 	uint getLineUni(uint32 *ubuf, uint len) override;
545 
546 	/**
547 	 * Cast a stream to a ScummVM write stream
548 	 */
549 	operator Common::WriteStream *() const override { return _outStream; }
550 
551 	/**
552 	 * Cast a stream to a ScummVM read stream
553 	 */
554 	operator Common::SeekableReadStream *() const override { return _inStream; }
555 };
556 
557 /**
558  * Implements a file stream
559  */
560 class FileStream : public IOStream {
561 private:
562 	Common::File _file;
563 	Common::InSaveFile *_inSave;
564 	Common::OutSaveFile *_outSave;
565 public:
566 	/**
567 	 * Constructor
568 	 */
569 	FileStream(Streams *streams, frefid_t fref, uint fmode, uint rock, bool unicode);
570 
571 	/**
572 	 * Destructor
573 	 */
574 	~FileStream() override;
575 };
576 
577 /**
578  * Streams manager
579  */
580 class Streams {
581 	friend class Stream;
582 private:
583 	Stream *_streamList;
584 	Stream *_currentStream;
585 	FileRefArray _fileReferences;
586 private:
587 	/**
588 	 * Adds a created stream to the list
589 	 */
590 	void addStream(Stream *stream);
591 
592 	/**
593 	 * Remove a stream
594 	 */
595 	void removeStream(Stream *stream);
596 public:
597 	/**
598 	 * Constructor
599 	 */
600 	Streams();
601 
602 	/**
603 	 * Destructor
604 	 */
605 	~Streams();
606 
607 	/**
608 	 * Open a file stream
609 	 */
610 	FileStream *openFileStream(frefid_t fref, uint fmode, uint rock = 0, bool unicode = false);
611 
612 	/**
613 	 * Open a ScummVM read stream
614 	 */
615 	IOStream *openStream(Common::SeekableReadStream *rs, uint rock = 0);
616 
617 	/**
618 	 * Open a ScummVM write stream
619 	 */
620 	IOStream *openStream(Common::WriteStream *ws, uint rock = 0);
621 
622 	/**
623 	 * Open a window stream
624 	 */
625 	WindowStream *openWindowStream(Window *window);
626 
627 	/**
628 	 * Open a memory stream
629 	 */
630 	MemoryStream *openMemoryStream(void *buf, size_t buflen, FileMode mode, uint rock = 0, bool unicode = true);
631 
632 	/**
633 	 * Delete a stream
634 	 */
deleteStream(Stream * stream)635 	void deleteStream(Stream *stream) {
636 		delete stream;
637 	}
638 
639 	/**
640 	 * Start an Iteration through streams
641 	 */
642 	Stream *getFirst(uint *rock);
643 
644 	/**
645 	 * Set the current output stream
646 	 */
setCurrent(Stream * stream)647 	void setCurrent(Stream *stream) {
648 		assert(!stream || stream->_writable);
649 		_currentStream = stream;
650 	}
651 
652 	/**
653 	 * Gets the current output stream
654 	 */
getCurrent()655 	Stream *getCurrent() const {
656 		return _currentStream;
657 	}
658 
659 	/**
660 	 * Prompt for a savegame to load or save, and populate a file reference from the result
661 	 */
662 	frefid_t createByPrompt(uint usage, FileMode fmode, uint rock);
663 
664 	/**
665 	 * Create a new file reference
666 	 */
667 	frefid_t createRef(int slot, const Common::String &desc, uint usage, uint rock);
668 
669 	/**
670 	 * Create a new file reference
671 	 */
672 	frefid_t createRef(const Common::String &filename, uint usage, uint rock);
673 
674 	/**
675 	 * Create a new temporary file reference
676 	 */
677 	frefid_t createTemp(uint usage, uint rock);
678 
679 	/**
680 	 * Create a new file reference from an old one
681 	 */
682 	frefid_t createFromRef(frefid_t fref, uint usage, uint rock);
683 
684 	/**
685 	 * Delete a file reference
686 	 */
687 	void deleteRef(frefid_t fref);
688 
689 	/**
690 	 * Iterates to the next file reference following the specified one,
691 	 * or the first if null is passed
692 	 */
693 	frefid_t iterate(frefid_t fref, uint *rock);
694 };
695 
696 } // End of namespace Glk
697 
698 #endif
699