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