ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

stream.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/ptr.h"
00024 #include "common/stream.h"
00025 #include "common/memstream.h"
00026 #include "common/substream.h"
00027 #include "common/str.h"
00028 
00029 namespace Common {
00030 
00031 void WriteStream::writeString(const String &str) {
00032     write(str.c_str(), str.size());
00033 }
00034 
00035 SeekableReadStream *ReadStream::readStream(uint32 dataSize) {
00036     void *buf = malloc(dataSize);
00037     dataSize = read(buf, dataSize);
00038     assert(dataSize > 0);
00039     return new MemoryReadStream((byte *)buf, dataSize, DisposeAfterUse::YES);
00040 }
00041 
00042 Common::String ReadStream::readPascalString(bool transformCR) {
00043     Common::String s;
00044     char *buf;
00045     int len;
00046     int i;
00047 
00048     len = readByte();
00049     buf = (char *)malloc(len + 1);
00050     for (i = 0; i < len; i++) {
00051         buf[i] = readByte();
00052         if (transformCR && buf[i] == 0x0d)
00053             buf[i] = '\n';
00054     }
00055 
00056     buf[i] = 0;
00057 
00058     s = buf;
00059     free(buf);
00060 
00061     return s;
00062 }
00063 
00064 uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) {
00065     // Read at most as many bytes as are still available...
00066     if (dataSize > _size - _pos) {
00067         dataSize = _size - _pos;
00068         _eos = true;
00069     }
00070     memcpy(dataPtr, _ptr, dataSize);
00071 
00072     _ptr += dataSize;
00073     _pos += dataSize;
00074 
00075     return dataSize;
00076 }
00077 
00078 bool MemoryReadStream::seek(int32 offs, int whence) {
00079     // Pre-Condition
00080     assert(_pos <= _size);
00081     switch (whence) {
00082     case SEEK_END:
00083         // SEEK_END works just like SEEK_SET, only 'reversed',
00084         // i.e. from the end.
00085         offs = _size + offs;
00086         // Fall through
00087     case SEEK_SET:
00088         _ptr = _ptrOrig + offs;
00089         _pos = offs;
00090         break;
00091 
00092     case SEEK_CUR:
00093         _ptr += offs;
00094         _pos += offs;
00095         break;
00096     }
00097     // Post-Condition
00098     assert(_pos <= _size);
00099 
00100     // Reset end-of-stream flag on a successful seek
00101     _eos = false;
00102     return true; // FIXME: STREAM REWRITE
00103 }
00104 
00105 bool MemoryWriteStreamDynamic::seek(int32 offs, int whence) {
00106     // Pre-Condition
00107     assert(_pos <= _size);
00108     switch (whence) {
00109     case SEEK_END:
00110         // SEEK_END works just like SEEK_SET, only 'reversed',
00111         // i.e. from the end.
00112         offs = _size + offs;
00113         // Fall through
00114     case SEEK_SET:
00115         _ptr = _data + offs;
00116         _pos = offs;
00117         break;
00118 
00119     case SEEK_CUR:
00120         _ptr += offs;
00121         _pos += offs;
00122         break;
00123     }
00124     // Post-Condition
00125     assert(_pos <= _size);
00126 
00127     return true; // FIXME: STREAM REWRITE
00128 }
00129 
00130 #pragma mark -
00131 
00132 enum {
00133     LF = 0x0A,
00134     CR = 0x0D
00135 };
00136 
00137 char *SeekableReadStream::readLine(char *buf, size_t bufSize) {
00138     assert(buf != nullptr && bufSize > 1);
00139     char *p = buf;
00140     size_t len = 0;
00141     char c = 0;
00142 
00143     // If end-of-file occurs before any characters are read, return NULL
00144     // and the buffer contents remain unchanged.
00145     if (eos() || err()) {
00146         return nullptr;
00147     }
00148 
00149     // Loop as long as there is still free space in the buffer,
00150     // and the line has not ended
00151     while (len + 1 < bufSize && c != LF) {
00152         c = readByte();
00153 
00154         if (eos()) {
00155             // If end-of-file occurs before any characters are read, return
00156             // NULL and the buffer contents remain unchanged.
00157             if (len == 0)
00158                 return nullptr;
00159 
00160             break;
00161         }
00162 
00163         // If an error occurs, return NULL and the buffer contents
00164         // are indeterminate.
00165         if (err())
00166             return nullptr;
00167 
00168         // Check for CR or CR/LF
00169         // * DOS and Windows use CRLF line breaks
00170         // * Unix and OS X use LF line breaks
00171         // * Macintosh before OS X used CR line breaks
00172         if (c == CR) {
00173             // Look at the next char -- is it LF? If not, seek back
00174             c = readByte();
00175 
00176             if (err()) {
00177                 return nullptr; // error: the buffer contents are indeterminate
00178             }
00179             if (eos()) {
00180                 // The CR was the last character in the file.
00181                 // Reset the eos() flag since we successfully finished a line
00182                 clearErr();
00183             } else if (c != LF) {
00184                 seek(-1, SEEK_CUR);
00185             }
00186 
00187             // Treat CR & CR/LF as plain LF
00188             c = LF;
00189         }
00190 
00191         *p++ = c;
00192         len++;
00193     }
00194 
00195     // We always terminate the buffer if no error occurred
00196     *p = 0;
00197     return buf;
00198 }
00199 
00200 String SeekableReadStream::readLine() {
00201     // Read a line
00202     String line;
00203     while (line.lastChar() != '\n') {
00204         char buf[256];
00205         if (!readLine(buf, 256))
00206             break;
00207         line += buf;
00208     }
00209 
00210     if (line.lastChar() == '\n')
00211         line.deleteLastChar();
00212 
00213     return line;
00214 }
00215 
00216 
00217 
00218 uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) {
00219     if (dataSize > _end - _pos) {
00220         dataSize = _end - _pos;
00221         _eos = true;
00222     }
00223 
00224     dataSize = _parentStream->read(dataPtr, dataSize);
00225     _pos += dataSize;
00226 
00227     return dataSize;
00228 }
00229 
00230 SeekableSubReadStream::SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, DisposeAfterUse::Flag disposeParentStream)
00231     : SubReadStream(parentStream, end, disposeParentStream),
00232     _parentStream(parentStream),
00233     _begin(begin) {
00234     assert(_begin <= _end);
00235     _pos = _begin;
00236     _parentStream->seek(_pos);
00237     _eos = false;
00238 }
00239 
00240 bool SeekableSubReadStream::seek(int32 offset, int whence) {
00241     assert(_pos >= _begin);
00242     assert(_pos <= _end);
00243 
00244     switch (whence) {
00245     case SEEK_END:
00246         offset = size() + offset;
00247         // fallthrough
00248     case SEEK_SET:
00249         _pos = _begin + offset;
00250         break;
00251     case SEEK_CUR:
00252         _pos += offset;
00253     }
00254 
00255     assert(_pos >= _begin);
00256     assert(_pos <= _end);
00257 
00258     bool ret = _parentStream->seek(_pos);
00259     if (ret) _eos = false; // reset eos on successful seek
00260 
00261     return ret;
00262 }
00263 
00264 uint32 SafeSeekableSubReadStream::read(void *dataPtr, uint32 dataSize) {
00265     // Make sure the parent stream is at the right position
00266     seek(0, SEEK_CUR);
00267 
00268     return SeekableSubReadStream::read(dataPtr, dataSize);
00269 }
00270 
00271 void SeekableReadStream::hexdump(int len, int bytesPerLine, int startOffset) {
00272     uint pos_ = pos();
00273     uint size_ = size();
00274     uint toRead = MIN<uint>(len + startOffset, size_ - pos_);
00275     byte *data = (byte *)calloc(toRead, 1);
00276 
00277     read(data, toRead);
00278     Common::hexdump(data, toRead, bytesPerLine, startOffset);
00279 
00280     free(data);
00281 
00282     seek(pos_);
00283 }
00284 
00285 #pragma mark -
00286 
00287 namespace {
00288 
00294 class BufferedReadStream : virtual public ReadStream {
00295 protected:
00296     DisposablePtr<ReadStream> _parentStream;
00297     byte *_buf;
00298     uint32 _pos;
00299     bool _eos; // end of stream
00300     uint32 _bufSize;
00301     uint32 _realBufSize;
00302 
00303 public:
00304     BufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream);
00305     virtual ~BufferedReadStream();
00306 
00307     virtual bool eos() const { return _eos; }
00308     virtual bool err() const { return _parentStream->err(); }
00309     virtual void clearErr() { _eos = false; _parentStream->clearErr(); }
00310 
00311     virtual uint32 read(void *dataPtr, uint32 dataSize);
00312 };
00313 
00314 BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream)
00315     : _parentStream(parentStream, disposeParentStream),
00316     _pos(0),
00317     _eos(false),
00318     _bufSize(0),
00319     _realBufSize(bufSize) {
00320 
00321     assert(parentStream);
00322     _buf = new byte[bufSize];
00323     assert(_buf);
00324 }
00325 
00326 BufferedReadStream::~BufferedReadStream() {
00327     delete[] _buf;
00328 }
00329 
00330 uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) {
00331     uint32 alreadyRead = 0;
00332     const uint32 bufBytesLeft = _bufSize - _pos;
00333 
00334     // Check whether the data left in the buffer suffices....
00335     if (dataSize > bufBytesLeft) {
00336         // Nope, we need to read more data
00337 
00338         // First, flush the buffer, if it is non-empty
00339         if (0 < bufBytesLeft) {
00340             memcpy(dataPtr, _buf + _pos, bufBytesLeft);
00341             _pos = _bufSize;
00342             alreadyRead += bufBytesLeft;
00343             dataPtr = (byte *)dataPtr + bufBytesLeft;
00344             dataSize -= bufBytesLeft;
00345         }
00346 
00347         // At this point the buffer is empty. Now if the read request
00348         // exceeds the buffer size, just satisfy it directly.
00349         if (dataSize > _realBufSize) {
00350             uint32 n = _parentStream->read(dataPtr, dataSize);
00351             if (_parentStream->eos())
00352                 _eos = true;
00353             return alreadyRead + n;
00354         }
00355 
00356         // Refill the buffer.
00357         // If we didn't read as many bytes as requested, the reason
00358         // is EOF or an error. In that case we truncate the buffer
00359         // size, as well as the number of  bytes we are going to
00360         // return to the caller.
00361         _bufSize = _parentStream->read(_buf, _realBufSize);
00362         _pos = 0;
00363         if (_bufSize < dataSize) {
00364             // we didn't get enough data from parent
00365             if (_parentStream->eos())
00366                 _eos = true;
00367             dataSize = _bufSize;
00368         }
00369     }
00370 
00371     if (dataSize) {
00372         // Satisfy the request from the buffer
00373         memcpy(dataPtr, _buf + _pos, dataSize);
00374         _pos += dataSize;
00375     }
00376     return alreadyRead + dataSize;
00377 }
00378 
00379 } // End of anonymous namespace
00380 
00381 
00382 ReadStream *wrapBufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream) {
00383     if (parentStream)
00384         return new BufferedReadStream(parentStream, bufSize, disposeParentStream);
00385     return nullptr;
00386 }
00387 
00388 #pragma mark -
00389 
00390 namespace {
00391 
00396 class BufferedSeekableReadStream : public BufferedReadStream, public SeekableReadStream {
00397 protected:
00398     SeekableReadStream *_parentStream;
00399 public:
00400     BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO);
00401 
00402     virtual int32 pos() const { return _parentStream->pos() - (_bufSize - _pos); }
00403     virtual int32 size() const { return _parentStream->size(); }
00404 
00405     virtual bool seek(int32 offset, int whence = SEEK_SET);
00406 };
00407 
00408 BufferedSeekableReadStream::BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream)
00409     : BufferedReadStream(parentStream, bufSize, disposeParentStream),
00410     _parentStream(parentStream) {
00411 }
00412 
00413 bool BufferedSeekableReadStream::seek(int32 offset, int whence) {
00414     // If it is a "local" seek, we may get away with "seeking" around
00415     // in the buffer only.
00416     _eos = false; // seeking always cancels EOS
00417 
00418     int relOffset = 0;
00419     switch (whence) {
00420     case SEEK_SET:
00421         relOffset = offset - pos();
00422         break;
00423     case SEEK_CUR:
00424         relOffset = offset;
00425         break;
00426     case SEEK_END:
00427         relOffset = (size() + offset) - pos();
00428         break;
00429     default:
00430         break;
00431     }
00432 
00433     if ((int)_pos + relOffset >= 0 && _pos + relOffset <= _bufSize) {
00434         _pos += relOffset;
00435 
00436         // Note: we do not need to reset parent's eos flag here. It is
00437         // sufficient that it is reset when actually seeking in the parent.
00438     } else {
00439         // Seek was not local enough, so we reset the buffer and
00440         // just seek normally in the parent stream.
00441         if (whence == SEEK_CUR)
00442             offset -= (_bufSize - _pos);
00443         // We invalidate the buffer here. This assures that successive seeks
00444         // do not have the chance to incorrectly think they seeked back into
00445         // the buffer.
00446         // Note: This does not take full advantage of the buffer. But it is
00447         // a simple way to prevent nasty errors. It would be possible to take
00448         // full advantage of the buffer by saving its actual start position.
00449         // This seems not worth the effort for this seemingly uncommon use.
00450         _pos = _bufSize = 0;
00451         _parentStream->seek(offset, whence);
00452     }
00453 
00454     return true;
00455 }
00456 
00457 } // End of anonymous namespace
00458 
00459 SeekableReadStream *wrapBufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream) {
00460     if (parentStream)
00461         return new BufferedSeekableReadStream(parentStream, bufSize, disposeParentStream);
00462     return nullptr;
00463 }
00464 
00465 #pragma mark -
00466 
00467 namespace {
00468 
00472 class BufferedWriteStream : public WriteStream {
00473 protected:
00474     WriteStream *_parentStream;
00475     byte *_buf;
00476     uint32 _pos;
00477     const uint32 _bufSize;
00478 
00486     bool flushBuffer() {
00487         const uint32 bytesToWrite = _pos;
00488 
00489         if (bytesToWrite) {
00490             _pos = 0;
00491             if (_parentStream->write(_buf, bytesToWrite) != bytesToWrite)
00492                 return false;
00493         }
00494         return true;
00495     }
00496 
00497 public:
00498     BufferedWriteStream(WriteStream *parentStream, uint32 bufSize)
00499         : _parentStream(parentStream),
00500         _pos(0),
00501         _bufSize(bufSize) {
00502 
00503         assert(parentStream);
00504         _buf = new byte[bufSize];
00505         assert(_buf);
00506     }
00507 
00508     virtual ~BufferedWriteStream() {
00509         const bool flushResult = flushBuffer();
00510         assert(flushResult);
00511 
00512         delete _parentStream;
00513 
00514         delete[] _buf;
00515     }
00516 
00517     virtual uint32 write(const void *dataPtr, uint32 dataSize) {
00518         // check if we have enough space for writing to the buffer
00519         if (_bufSize - _pos >= dataSize) {
00520             memcpy(_buf + _pos, dataPtr, dataSize);
00521             _pos += dataSize;
00522         } else if (_bufSize >= dataSize) {  // check if we can flush the buffer and load the data
00523             const bool flushResult = flushBuffer();
00524             assert(flushResult);
00525             memcpy(_buf, dataPtr, dataSize);
00526             _pos += dataSize;
00527         } else  {   // too big for our buffer
00528             const bool flushResult = flushBuffer();
00529             assert(flushResult);
00530             return _parentStream->write(dataPtr, dataSize);
00531         }
00532         return dataSize;
00533     }
00534 
00535     virtual bool flush() { return flushBuffer(); }
00536 
00537     virtual int32 pos() const { return _pos; }
00538 
00539 };
00540 
00541 } // End of anonymous namespace
00542 
00543 WriteStream *wrapBufferedWriteStream(WriteStream *parentStream, uint32 bufSize) {
00544     if (parentStream)
00545         return new BufferedWriteStream(parentStream, bufSize);
00546     return nullptr;
00547 }
00548 
00549 } // End of namespace Common


Generated on Sat Mar 16 2019 05:01:55 for ResidualVM by doxygen 1.7.1
curved edge   curved edge