* Added new virtual base class 'Stream', ReadStream and

WriteStream are now subclasses of it.
* Added new methods eos(), ioFailed(), clearIOFailed() to
  all streams. This allows better error checking.
* SaveFile classes take advantage of these new standard
  stream APIS
* Removed File::gets()
* Added SeekableReadStream::readLine() (replaces File::gets)
* Added WriteStream::writeString, for convenience

svn-id: r17752
This commit is contained in:
Max Horn 2005-04-22 17:40:09 +00:00
parent ca33ec4563
commit 969ef3dac9
12 changed files with 126 additions and 89 deletions

View file

@ -278,68 +278,3 @@ uint32 File::write(const void *ptr, uint32 len) {
return len;
}
#define LF 0x0A
#define CR 0x0D
char *File::gets(void *ptr, uint32 len) {
char *ptr2 = (char *)ptr;
char *res = ptr2;
uint32 read_chars = 1;
if (_handle == NULL) {
error("File::gets: File is not open!");
return 0;
}
if (len == 0 || !ptr)
return NULL;
// We don't include the newline character(s) in the buffer, and we
// always terminate it - we never read more than len-1 characters.
// EOF is treated as a line break, unless it was the first character
// that was read.
// 0 is treated as a line break, even though it should never occur in
// a text file.
// DOS and Windows use CRLF line breaks
// Unix and OS X use LF line breaks
// Macintosh before OS X uses CR line breaks
bool first = true;
while (read_chars < len) {
int c = getc(_handle);
if (c == EOF) {
if (first)
return NULL;
break;
}
first = false;
if (c == 0)
break;
if (c == LF)
break;
if (c == CR) {
c = getc(_handle);
// Don't use ungetc() here. It might be slightly more
// elegant, but PalmOS doesn't have it.
if (c != LF && c != EOF)
fseek(_handle, -1, SEEK_CUR);
break;
}
*ptr2++ = (char) c;
read_chars++;
}
*ptr2 = 0;
return res;
}

View file

@ -66,6 +66,7 @@ public:
bool isOpen() const;
bool ioFailed() const;
void clearIOFailed();
bool eos() const { return eof(); }
bool eof() const;
uint32 pos() const;
uint32 size() const;
@ -73,7 +74,6 @@ public:
void seek(int32 offs, int whence = SEEK_SET);
uint32 read(void *ptr, uint32 size);
uint32 write(const void *ptr, uint32 size);
char *gets(void *ptr, uint32 size);
};
#endif

View file

@ -73,8 +73,10 @@ public:
::fclose(fh);
}
bool readingFailed() const { return ferror(fh) != 0; }
bool writingFailed() const { return ferror(fh) != 0; }
bool eos() const { return feof(fh) != 0; }
bool ioFailed() const { return ferror(fh) != 0; }
void clearIOFailed() { clearerr(fh); }
bool isOpen() const { return fh != 0; }
uint32 read(void *buf, uint32 cnt) {
@ -101,8 +103,10 @@ public:
::gzclose(fh);
}
bool readingFailed() const { return _ioError; }
bool writingFailed() const { return _ioError; }
bool eos() const { return gzeof(fh) != 0; }
bool ioFailed() const { return _ioError; }
void clearIOFailed() { _ioError = false; }
bool isOpen() const { return fh != 0; }
uint32 read(void *buf, uint32 cnt) {

View file

@ -40,9 +40,6 @@
class InSaveFile : public Common::ReadStream {
public:
virtual ~InSaveFile() {}
virtual bool readingFailed() const { return false; }
//bool eof() const;
};
/**
@ -55,8 +52,6 @@ public:
class OutSaveFile : public Common::WriteStream {
public:
virtual ~OutSaveFile() {}
virtual bool writingFailed() const { return false; }
};
/**

View file

@ -21,9 +21,13 @@
#include "stdafx.h"
#include "common/stream.h"
#include "common/str.h"
namespace Common {
void WriteStream::writeString(const String &str) {
write(str.c_str(), str.size());
}
void MemoryReadStream::seek(int32 offs, int whence) {
// Pre-Condition
@ -48,5 +52,62 @@ void MemoryReadStream::seek(int32 offs, int whence) {
assert(_pos <= _bufSize);
}
#define LF 0x0A
#define CR 0x0D
char *SeekableReadStream::readLine(char *buf, size_t bufSize) {
assert(buf && bufSize > 0);
char *p = buf;
size_t len = 0;
char c;
if (buf == 0 || bufSize == 0 || eos()) {
return 0;
}
// We don't include the newline character(s) in the buffer, and we
// always terminate it - we never read more than len-1 characters.
// EOF is treated as a line break, unless it was the first character
// that was read.
// 0 is treated as a line break, even though it should never occur in
// a text file.
// DOS and Windows use CRLF line breaks
// Unix and OS X use LF line breaks
// Macintosh before OS X uses CR line breaks
c = readByte();
if (eos() || ioFailed()) {
return 0;
}
while (!eos() && len + 1 < bufSize) {
if (ioFailed())
return 0;
if (c == 0 || c == LF)
break;
if (c == CR) {
c = readByte();
if (c != LF && !eos())
seek(-1, SEEK_CUR);
break;
}
*p++ = c;
len++;
c = readByte();
}
*p = 0;
return buf;
}
} // End of namespace Common

View file

@ -28,10 +28,38 @@
namespace Common {
class String;
/**
* Virtual base class for both ReadStream and WriteStream.
*/
class Stream {
public:
/**
* Returns true if the end of the stream has been reached.
*/
virtual bool eos() const = 0;
/**
* Returns true if any I/O failure occured.
* This flag is never cleared automatically. In order to clear it,
* client code has to call clearIOFailed() explicitly.
*
* @todo Instead of returning a plain bool, maybe we should define
* a list of error codes which can be returned here.
*/
virtual bool ioFailed() const { return false; }
/**
* Reset the I/O error status.
*/
virtual void clearIOFailed() {}
};
/**
* Generic interface for a writable data stream.
*/
class WriteStream {
class WriteStream : virtual public Stream {
public:
/**
* Write data into the stream. Subclasses must implement this
@ -90,13 +118,15 @@ public:
void writeSint32BE(int32 value) {
writeUint32BE((uint32)value);
}
void writeString(const String &str);
};
/**
* Generic interface for a readable data stream.
*/
class ReadStream {
class ReadStream : virtual public Stream {
public:
/**
* Read data from the stream. Subclasses must implement this
@ -175,11 +205,22 @@ public:
class SeekableReadStream : public ReadStream {
public:
virtual bool eof() const = 0;
virtual uint32 pos() const = 0;
virtual uint32 size() const = 0;
virtual void seek(int32 offs, int whence = SEEK_SET) = 0;
/**
* Read one line of text from a CR or CR/LF terminated plain text file.
* This method is a rough analog of the (f)gets function.
*
* @param buf the buffer to store into
* @param size the size of the buffer
* @return a pointer to the read string, or NULL if an error occured
* @note The line terminator (CR or CR/LF) is stripped and not inserted
* into the buffer.
*/
virtual char *readLine(char *buf, size_t bufSize);
};
@ -200,6 +241,10 @@ public:
void setStream(ReadStream *in) { _realStream = in; }
void setEnc(byte value) { _encbyte = value; }
virtual bool eos() const { return _realStream->eos(); }
virtual bool ioFailed() const { return _realStream->ioFailed(); }
virtual void clearIOFailed() { _realStream->clearIOFailed(); }
uint32 read(void *ptr, uint32 size) {
assert(_realStream);
uint32 len = _realStream->read(ptr, size);
@ -249,7 +294,7 @@ public:
return len;
}
bool eof() const { return _pos == _bufSize; }
bool eos() const { return _pos == _bufSize; }
uint32 pos() const { return _pos; }
uint32 size() const { return _bufSize; }
@ -279,7 +324,7 @@ public:
return len;
}
bool eof() const { return _pos == _bufSize; }
bool eos() const { return _pos == _bufSize; }
uint32 pos() const { return _pos; }
uint32 size() const { return _bufSize; }
};

View file

@ -413,10 +413,7 @@ void VMContext::loadScript(const char* file) {
uint8 chunkName[sizeof("EMC2ORDR") + 1];
// so lets look for our chunks :)
while(true) {
if (script.eof()) {
break;
}
while (!script.eos()) {
// lets read only the first 4 chars
script.read(chunkName, sizeof(uint8) * 4);
chunkName[4] = '\0';

View file

@ -402,7 +402,7 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou
MemoryReadStream readS(inputBuffer, inLength);
while (!readS.eof() && (outPointer < outPointerEnd)) {
while (!readS.eos() && (outPointer < outPointerEnd)) {
bg_runcount = readS.readByte();
fg_runcount = readS.readByte();

View file

@ -100,7 +100,7 @@ public:
bool openSubFile(const char *filename);
void close();
bool eof() { return _stream->eof(); }
bool eof() { return _stream->eos(); }
uint32 pos() { return _stream->pos(); }
uint32 size() { return _stream->size(); }
void seek(int32 offs, int whence = SEEK_SET) { _stream->seek(offs, whence); }

View file

@ -590,7 +590,7 @@ bool SimonEngine::load_game(uint slot) {
for (i = 0; i != 32; i++)
_bit_array[i] = f->readUint16BE();
if (f->readingFailed()) {
if (f->ioFailed()) {
error("load failed");
}

View file

@ -90,7 +90,7 @@ public:
return file.read(in, size);
}
bool readLine(char *in, size_t size) {
return file.gets(in, size) != NULL;
return file.readLine(in, size) != NULL;
}
bool readBit8u(MT32Emu::Bit8u *in) {
byte b = file.readByte();

View file

@ -3032,7 +3032,7 @@ int32 Logic::fnPlayCredits(int32 *params) {
}
char buffer[80];
char *line = f.gets(buffer, sizeof(buffer));
char *line = f.readLine(buffer, sizeof(buffer));
if (!line || *line == 0) {
if (!hasCenterMark) {