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 "common/ptr.h"
24 #include "common/stream.h"
25 #include "common/memstream.h"
26 #include "common/substream.h"
27 #include "common/str.h"
28 
29 namespace Common {
30 
writeStream(ReadStream * stream,uint32 dataSize)31 uint32 WriteStream::writeStream(ReadStream *stream, uint32 dataSize) {
32 	void *buf = malloc(dataSize);
33 	dataSize = stream->read(buf, dataSize);
34 	assert(dataSize > 0);
35 	dataSize = write(buf, dataSize);
36 	free(buf);
37 	return dataSize;
38 }
39 
writeStream(SeekableReadStream * stream)40 uint32 WriteStream::writeStream(SeekableReadStream *stream) {
41 	return writeStream(stream, stream->size());
42 }
43 
writeString(const String & str)44 void WriteStream::writeString(const String &str) {
45 	write(str.c_str(), str.size());
46 }
47 
readStream(uint32 dataSize)48 SeekableReadStream *ReadStream::readStream(uint32 dataSize) {
49 	void *buf = malloc(dataSize);
50 	dataSize = read(buf, dataSize);
51 	assert(dataSize > 0);
52 	return new MemoryReadStream((byte *)buf, dataSize, DisposeAfterUse::YES);
53 }
54 
readString(char terminator,size_t len)55 Common::String ReadStream::readString(char terminator, size_t len) {
56 	Common::String result;
57 	char c;
58 	bool end = false;
59 	size_t bytesRead = 0;
60 
61 	while (bytesRead < len && !(end && len == Common::String::npos)) {
62 		c = (char)readByte();
63 		if (eos())
64 			break;
65 		if (c == terminator)
66 			end = true;
67 		if (!end)
68 			result += c;
69 		bytesRead++;
70 	}
71 
72 	return result;
73 }
74 
readPascalString(bool transformCR)75 Common::String ReadStream::readPascalString(bool transformCR) {
76 	Common::String s;
77 	char *buf;
78 	int len;
79 	int i;
80 
81 	len = readByte();
82 	buf = (char *)malloc(len + 1);
83 	for (i = 0; i < len; i++) {
84 		buf[i] = readByte();
85 		if (transformCR && buf[i] == 0x0d)
86 			buf[i] = '\n';
87 	}
88 
89 	buf[i] = 0;
90 
91 	s = buf;
92 	free(buf);
93 
94 	return s;
95 }
96 
read(void * dataPtr,uint32 dataSize)97 uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) {
98 	// Read at most as many bytes as are still available...
99 	if (dataSize > _size - _pos) {
100 		dataSize = _size - _pos;
101 		_eos = true;
102 	}
103 	memcpy(dataPtr, _ptr, dataSize);
104 
105 	_ptr += dataSize;
106 	_pos += dataSize;
107 
108 	return dataSize;
109 }
110 
seek(int64 offs,int whence)111 bool MemoryReadStream::seek(int64 offs, int whence) {
112 	// Pre-Condition
113 	assert(_pos <= _size);
114 	switch (whence) {
115 	case SEEK_END:
116 		// SEEK_END works just like SEEK_SET, only 'reversed',
117 		// i.e. from the end.
118 		offs = _size + offs;
119 		// Fall through
120 	case SEEK_SET:
121 		// Fall through
122 	default:
123 		_ptr = _ptrOrig + offs;
124 		_pos = offs;
125 		break;
126 
127 	case SEEK_CUR:
128 		_ptr += offs;
129 		_pos += offs;
130 		break;
131 	}
132 	// Post-Condition
133 	assert(_pos <= _size);
134 
135 	// Reset end-of-stream flag on a successful seek
136 	_eos = false;
137 	return true; // FIXME: STREAM REWRITE
138 }
139 
140 #pragma mark -
141 
142 enum {
143 	LF = 0x0A,
144 	CR = 0x0D
145 };
146 
readLine(char * buf,size_t bufSize,bool handleCR)147 char *SeekableReadStream::readLine(char *buf, size_t bufSize, bool handleCR) {
148 	assert(buf != nullptr && bufSize > 1);
149 	char *p = buf;
150 	size_t len = 0;
151 	char c = 0;
152 
153 	// If end-of-file occurs before any characters are read, return NULL
154 	// and the buffer contents remain unchanged.
155 	if (eos() || err()) {
156 		return nullptr;
157 	}
158 
159 	// Loop as long as there is still free space in the buffer,
160 	// and the line has not ended
161 	while (len + 1 < bufSize && c != LF) {
162 		c = readByte();
163 
164 		if (eos()) {
165 			// If end-of-file occurs before any characters are read, return
166 			// NULL and the buffer contents remain unchanged.
167 			if (len == 0)
168 				return nullptr;
169 
170 			break;
171 		}
172 
173 		// If an error occurs, return NULL and the buffer contents
174 		// are indeterminate.
175 		if (err())
176 			return nullptr;
177 
178 		// Check for CR or CR/LF
179 		// * DOS and Windows use CRLF line breaks
180 		// * Unix and OS X use LF line breaks
181 		// * Macintosh before OS X used CR line breaks
182 		if (c == CR && handleCR) {
183 			// Look at the next char -- is it LF? If not, seek back
184 			c = readByte();
185 
186 			if (err()) {
187 				return nullptr; // error: the buffer contents are indeterminate
188 			}
189 			if (eos()) {
190 				// The CR was the last character in the file.
191 				// Reset the eos() flag since we successfully finished a line
192 				clearErr();
193 			} else if (c != LF) {
194 				seek(-1, SEEK_CUR);
195 			}
196 
197 			// Treat CR & CR/LF as plain LF
198 			c = LF;
199 		}
200 
201 		*p++ = c;
202 		len++;
203 	}
204 
205 	// We always terminate the buffer if no error occurred
206 	*p = 0;
207 	return buf;
208 }
209 
readLine(bool handleCR)210 String SeekableReadStream::readLine(bool handleCR) {
211 	// Read a line
212 	String line;
213 	while (line.lastChar() != '\n') {
214 		char buf[256];
215 		if (!readLine(buf, 256, handleCR))
216 			break;
217 		line += buf;
218 	}
219 
220 	if (line.lastChar() == '\n')
221 		line.deleteLastChar();
222 
223 	return line;
224 }
225 
read(void * dataPtr,uint32 dataSize)226 uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) {
227 	if (dataSize > _end - _pos) {
228 		dataSize = _end - _pos;
229 		_eos = true;
230 	}
231 
232 	dataSize = _parentStream->read(dataPtr, dataSize);
233 	_pos += dataSize;
234 
235 	return dataSize;
236 }
237 
SeekableSubReadStream(SeekableReadStream * parentStream,uint32 begin,uint32 end,DisposeAfterUse::Flag disposeParentStream)238 SeekableSubReadStream::SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, DisposeAfterUse::Flag disposeParentStream)
239 	: SubReadStream(parentStream, end, disposeParentStream),
240 	_parentStream(parentStream),
241 	_begin(begin) {
242 	assert(_begin <= _end);
243 	_pos = _begin;
244 	_parentStream->seek(_pos);
245 	_eos = false;
246 }
247 
seek(int64 offset,int whence)248 bool SeekableSubReadStream::seek(int64 offset, int whence) {
249 	assert(_pos >= _begin);
250 	assert(_pos <= _end);
251 
252 	switch (whence) {
253 	case SEEK_END:
254 		offset = size() + offset;
255 		// fallthrough
256 	case SEEK_SET:
257 		// Fall through
258 	default:
259 		_pos = _begin + offset;
260 		break;
261 	case SEEK_CUR:
262 		_pos += offset;
263 	}
264 
265 	assert(_pos >= _begin);
266 	assert(_pos <= _end);
267 
268 	bool ret = _parentStream->seek(_pos);
269 	if (ret) _eos = false; // reset eos on successful seek
270 
271 	return ret;
272 }
273 
read(void * dataPtr,uint32 dataSize)274 uint32 SafeSeekableSubReadStream::read(void *dataPtr, uint32 dataSize) {
275 	// Make sure the parent stream is at the right position
276 	seek(0, SEEK_CUR);
277 
278 	return SeekableSubReadStream::read(dataPtr, dataSize);
279 }
280 
hexdump(int len,int bytesPerLine,int startOffset)281 void SeekableReadStream::hexdump(int len, int bytesPerLine, int startOffset) {
282 	uint pos_ = pos();
283 	uint size_ = size();
284 	uint toRead = MIN<uint>(len + startOffset, size_ - pos_);
285 	byte *data = (byte *)calloc(toRead, 1);
286 
287 	read(data, toRead);
288 	Common::hexdump(data, toRead, bytesPerLine, startOffset);
289 
290 	free(data);
291 
292 	seek(pos_);
293 }
294 
295 #pragma mark -
296 
297 namespace {
298 
299 /**
300  * Wrapper class which adds buffering to any given ReadStream.
301  * Users can specify how big the buffer should be, and whether the
302  * wrapped stream should be disposed when the wrapper is disposed.
303  */
304 class BufferedReadStream : virtual public ReadStream {
305 protected:
306 	DisposablePtr<ReadStream> _parentStream;
307 	byte *_buf;
308 	uint32 _pos;
309 	bool _eos; // end of stream
310 	uint32 _bufSize;
311 	uint32 _realBufSize;
312 
313 public:
314 	BufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream);
315 	virtual ~BufferedReadStream();
316 
eos() const317 	virtual bool eos() const { return _eos; }
err() const318 	virtual bool err() const { return _parentStream->err(); }
clearErr()319 	virtual void clearErr() { _eos = false; _parentStream->clearErr(); }
320 
321 	virtual uint32 read(void *dataPtr, uint32 dataSize);
322 };
323 
BufferedReadStream(ReadStream * parentStream,uint32 bufSize,DisposeAfterUse::Flag disposeParentStream)324 BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream)
325 	: _parentStream(parentStream, disposeParentStream),
326 	_pos(0),
327 	_eos(false),
328 	_bufSize(0),
329 	_realBufSize(bufSize) {
330 
331 	assert(parentStream);
332 	_buf = new byte[bufSize];
333 	assert(_buf);
334 }
335 
~BufferedReadStream()336 BufferedReadStream::~BufferedReadStream() {
337 	delete[] _buf;
338 }
339 
read(void * dataPtr,uint32 dataSize)340 uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) {
341 	uint32 alreadyRead = 0;
342 	const uint32 bufBytesLeft = _bufSize - _pos;
343 
344 	// Check whether the data left in the buffer suffices....
345 	if (dataSize > bufBytesLeft) {
346 		// Nope, we need to read more data
347 
348 		// First, flush the buffer, if it is non-empty
349 		if (0 < bufBytesLeft) {
350 			memcpy(dataPtr, _buf + _pos, bufBytesLeft);
351 			_pos = _bufSize;
352 			alreadyRead += bufBytesLeft;
353 			dataPtr = (byte *)dataPtr + bufBytesLeft;
354 			dataSize -= bufBytesLeft;
355 		}
356 
357 		// At this point the buffer is empty. Now if the read request
358 		// exceeds the buffer size, just satisfy it directly.
359 		if (dataSize > _realBufSize) {
360 			uint32 n = _parentStream->read(dataPtr, dataSize);
361 			if (_parentStream->eos())
362 				_eos = true;
363 
364 			// Fill the buffer from the user buffer so a seek back in
365 			// the stream into the buffered area brings consistent data.
366 			_bufSize = MIN(n, _realBufSize);
367 			_pos = _bufSize;
368 			memcpy(_buf, (byte *)dataPtr + n - _bufSize, _bufSize);
369 
370 			return alreadyRead + n;
371 		}
372 
373 		// Refill the buffer.
374 		// If we didn't read as many bytes as requested, the reason
375 		// is EOF or an error. In that case we truncate the buffer
376 		// size, as well as the number of  bytes we are going to
377 		// return to the caller.
378 		_bufSize = _parentStream->read(_buf, _realBufSize);
379 		_pos = 0;
380 		if (_bufSize < dataSize) {
381 			// we didn't get enough data from parent
382 			if (_parentStream->eos())
383 				_eos = true;
384 			dataSize = _bufSize;
385 		}
386 	}
387 
388 	if (dataSize) {
389 		// Satisfy the request from the buffer
390 		memcpy(dataPtr, _buf + _pos, dataSize);
391 		_pos += dataSize;
392 	}
393 	return alreadyRead + dataSize;
394 }
395 
396 } // End of anonymous namespace
397 
398 
wrapBufferedReadStream(ReadStream * parentStream,uint32 bufSize,DisposeAfterUse::Flag disposeParentStream)399 ReadStream *wrapBufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream) {
400 	if (parentStream)
401 		return new BufferedReadStream(parentStream, bufSize, disposeParentStream);
402 	return nullptr;
403 }
404 
405 #pragma mark -
406 
407 namespace {
408 
409 /**
410  * Wrapper class which adds buffering to any given SeekableReadStream.
411  * @see BufferedReadStream
412  */
413 class BufferedSeekableReadStream : public BufferedReadStream, public SeekableReadStream {
414 protected:
415 	SeekableReadStream *_parentStream;
416 public:
417 	BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO);
418 
pos() const419 	virtual int64 pos() const { return _parentStream->pos() - (_bufSize - _pos); }
size() const420 	virtual int64 size() const { return _parentStream->size(); }
421 
422 	virtual bool seek(int64 offset, int whence = SEEK_SET);
423 };
424 
BufferedSeekableReadStream(SeekableReadStream * parentStream,uint32 bufSize,DisposeAfterUse::Flag disposeParentStream)425 BufferedSeekableReadStream::BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream)
426 	: BufferedReadStream(parentStream, bufSize, disposeParentStream),
427 	_parentStream(parentStream) {
428 }
429 
seek(int64 offset,int whence)430 bool BufferedSeekableReadStream::seek(int64 offset, int whence) {
431 	// If it is a "local" seek, we may get away with "seeking" around
432 	// in the buffer only.
433 	_eos = false; // seeking always cancels EOS
434 
435 	int relOffset = 0;
436 	switch (whence) {
437 	case SEEK_SET:
438 		relOffset = offset - pos();
439 		break;
440 	case SEEK_CUR:
441 		relOffset = offset;
442 		break;
443 	case SEEK_END:
444 		relOffset = (size() + offset) - pos();
445 		break;
446 	default:
447 		break;
448 	}
449 
450 	if ((int)_pos + relOffset >= 0 && _pos + relOffset <= _bufSize) {
451 		_pos += relOffset;
452 
453 		// Note: we do not need to reset parent's eos flag here. It is
454 		// sufficient that it is reset when actually seeking in the parent.
455 	} else {
456 		// Seek was not local enough, so we reset the buffer and
457 		// just seek normally in the parent stream.
458 		if (whence == SEEK_CUR)
459 			offset -= (_bufSize - _pos);
460 		// We invalidate the buffer here. This assures that successive seeks
461 		// do not have the chance to incorrectly think they seeked back into
462 		// the buffer.
463 		// Note: This does not take full advantage of the buffer. But it is
464 		// a simple way to prevent nasty errors. It would be possible to take
465 		// full advantage of the buffer by saving its actual start position.
466 		// This seems not worth the effort for this seemingly uncommon use.
467 		_pos = _bufSize = 0;
468 		_parentStream->seek(offset, whence);
469 	}
470 
471 	return true;
472 }
473 
474 } // End of anonymous namespace
475 
wrapBufferedSeekableReadStream(SeekableReadStream * parentStream,uint32 bufSize,DisposeAfterUse::Flag disposeParentStream)476 SeekableReadStream *wrapBufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream) {
477 	if (parentStream)
478 		return new BufferedSeekableReadStream(parentStream, bufSize, disposeParentStream);
479 	return nullptr;
480 }
481 
482 #pragma mark -
483 
484 namespace {
485 
486 /**
487  * Wrapper class which adds buffering to any WriteStream.
488  */
489 class BufferedWriteStream : public SeekableWriteStream {
490 protected:
491 	WriteStream *_parentStream;
492 	byte *_buf;
493 	uint32 _pos;
494 	const uint32 _bufSize;
495 
496 	/**
497 	 * Write out the data in the buffer.
498 	 *
499 	 * @note This method is identical to flush() (which actually is
500 	 * implemented by calling this method), except that it is not
501 	 * virtual, hence there is less overhead calling it.
502 	 */
flushBuffer()503 	bool flushBuffer() {
504 		const uint32 bytesToWrite = _pos;
505 
506 		if (bytesToWrite) {
507 			_pos = 0;
508 			if (_parentStream->write(_buf, bytesToWrite) != bytesToWrite)
509 				return false;
510 		}
511 		return true;
512 	}
513 
514 public:
BufferedWriteStream(WriteStream * parentStream,uint32 bufSize)515 	BufferedWriteStream(WriteStream *parentStream, uint32 bufSize)
516 		: _parentStream(parentStream),
517 		_pos(0),
518 		_bufSize(bufSize) {
519 
520 		assert(parentStream);
521 		_buf = new byte[bufSize];
522 		assert(_buf);
523 	}
524 
~BufferedWriteStream()525 	virtual ~BufferedWriteStream() {
526 		const bool flushResult = flushBuffer();
527 		assert(flushResult);
528 
529 		delete _parentStream;
530 
531 		delete[] _buf;
532 	}
533 
write(const void * dataPtr,uint32 dataSize)534 	uint32 write(const void *dataPtr, uint32 dataSize) override {
535 		// check if we have enough space for writing to the buffer
536 		if (_bufSize - _pos >= dataSize) {
537 			memcpy(_buf + _pos, dataPtr, dataSize);
538 			_pos += dataSize;
539 		} else if (_bufSize >= dataSize) {	// check if we can flush the buffer and load the data
540 			const bool flushResult = flushBuffer();
541 			assert(flushResult);
542 			memcpy(_buf, dataPtr, dataSize);
543 			_pos += dataSize;
544 		} else	{	// too big for our buffer
545 			const bool flushResult = flushBuffer();
546 			assert(flushResult);
547 			return _parentStream->write(dataPtr, dataSize);
548 		}
549 		return dataSize;
550 	}
551 
flush()552 	bool flush() override { return flushBuffer(); }
553 
pos() const554 	int64 pos() const override { return _pos; }
555 
seek(int64 offset,int whence)556 	bool seek(int64 offset, int whence) override {
557 		flush();
558 
559 		Common::SeekableWriteStream *sws =
560 			dynamic_cast<Common::SeekableWriteStream *>(_parentStream);
561 		return sws ? sws->seek(offset, whence) : false;
562 	}
563 
size() const564 	int64 size() const override {
565 		Common::SeekableWriteStream *sws =
566 			dynamic_cast<Common::SeekableWriteStream *>(_parentStream);
567 		return sws ? MAX(sws->pos() + _pos, sws->size()) : -1;
568 	}
569 };
570 
571 } // End of anonymous namespace
572 
wrapBufferedWriteStream(SeekableWriteStream * parentStream,uint32 bufSize)573 SeekableWriteStream *wrapBufferedWriteStream(SeekableWriteStream *parentStream, uint32 bufSize) {
574 	if (parentStream)
575 		return new BufferedWriteStream(parentStream, bufSize);
576 	return nullptr;
577 }
578 
wrapBufferedWriteStream(WriteStream * parentStream,uint32 bufSize)579 WriteStream *wrapBufferedWriteStream(WriteStream *parentStream, uint32 bufSize) {
580 	if (parentStream)
581 		return new BufferedWriteStream(parentStream, bufSize);
582 	return nullptr;
583 }
584 
585 } // End of namespace Common
586