Skip to content

Commit

Permalink
Refactor|libdeng2: Files are I/O streams instead of byte arrays
Browse files Browse the repository at this point in the history
IIOStream is an interface that provides access to an object through
a stream of bytes.

Changed the interface of de::File, the base class for all files,
from IByteArray to IIOStream. While many files are byte array based,
there are also other kinds of files that behave like streams
(cf. UNIX sockets, character devices).

Added ByteArrayFile: an abstract base class for random-access byte
array based files, where the I/O stream has a default implementation
that accesses the file's contents (as a byte array).

Block, Writer, and Reader constructors accept I/O streams as
source/destination objects.

Refactored Reader's rewind mechanism to work also with streams.

Applied the pimpl idiom in Reader, Writer, and ArchiveFeed.

Updated the rest of libdeng2 accordingly.
  • Loading branch information
skyjake committed Nov 22, 2012
1 parent 4d5f28c commit e1e1d7c
Show file tree
Hide file tree
Showing 31 changed files with 850 additions and 267 deletions.
2 changes: 2 additions & 0 deletions doomsday/libdeng2/data.pri
Expand Up @@ -16,6 +16,7 @@ HEADERS += \
include/de/Guard \
include/de/IBlock \
include/de/IByteArray \
include/de/IIOStream \
include/de/IReadable \
include/de/ISerializable \
include/de/IWritable \
Expand Down Expand Up @@ -54,6 +55,7 @@ HEADERS += \
include/de/data/huffman.h \
include/de/data/iblock.h \
include/de/data/ibytearray.h \
include/de/data/iiostream.h \
include/de/data/info.h \
include/de/data/ireadable.h \
include/de/data/iserializable.h \
Expand Down
3 changes: 3 additions & 0 deletions doomsday/libdeng2/filesys.pri
@@ -1,6 +1,7 @@
HEADERS += \
include/de/ArchiveFeed \
include/de/ArchiveFile \
include/de/ByteArrayFile \
include/de/DirectoryFeed \
include/de/Feed \
include/de/File \
Expand All @@ -11,6 +12,7 @@ HEADERS += \
include/de/NativePath \
include/de/filesys/archivefeed.h \
include/de/filesys/archivefile.h \
include/de/filesys/bytearrayfile.h \
include/de/filesys/directoryfeed.h \
include/de/filesys/feed.h \
include/de/filesys/file.h \
Expand All @@ -23,6 +25,7 @@ HEADERS += \
SOURCES += \
src/filesys/archivefeed.cpp \
src/filesys/archivefile.cpp \
src/filesys/bytearrayfile.cpp \
src/filesys/directoryfeed.cpp \
src/filesys/feed.cpp \
src/filesys/file.cpp \
Expand Down
1 change: 1 addition & 0 deletions doomsday/libdeng2/include/de/ByteArrayFile
@@ -0,0 +1 @@
#include "filesys/bytearrayfile.h"
1 change: 1 addition & 0 deletions doomsday/libdeng2/include/de/IIOStream
@@ -0,0 +1 @@
#include "data/iiostream.h"
22 changes: 21 additions & 1 deletion doomsday/libdeng2/include/de/data/block.h
Expand Up @@ -27,8 +27,10 @@

namespace de {

class IIOStream;

/**
* Simple data buffer that implements the byte array interface.
* Data buffer that implements the byte array interface.
*
* @ingroup data
*/
Expand All @@ -40,6 +42,24 @@ class DENG2_PUBLIC Block : public QByteArray, public IByteArray, public IBlock
Block(const Block& other);
Block(const QByteArray& byteArray);

/**
* Constructs a block by reading the contents of an I/O stream. The block
* will contain all the data that is available immediately; will not wait
* for additional data to become available later.
*
* @param stream Stream to read from.
*/
Block(IIOStream& stream);

/**
* Constructs a block by reading the contents of a I/O stream in const
* mode. The block will contain all the data that is available immediately;
* will not wait for additional data to become available later.
*
* @param stream Stream to read from.
*/
Block(const IIOStream& stream);

/**
* Construct a new block and copy its contents from the specified
* location at another array.
Expand Down
90 changes: 90 additions & 0 deletions doomsday/libdeng2/include/de/data/iiostream.h
@@ -0,0 +1,90 @@
/**
* @file iiostream.h
* I/O stream interface. @ingroup data
*
* @authors Copyright © 2012 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDENG2_IIOSTREAM_H
#define LIBDENG2_IIOSTREAM_H

#include "../IByteArray"

namespace de {

/**
* Interface that allows communication via an input/output stream of bytes.
*
* When reading from a stream, the stream can either be in modifiable
* (non-const) or immutable (const) mode. When reading bytes from a modifiable
* stream, the bytes are then removed from the stream and the next read will
* return a different set of bytes. Immutable streams, on the other hand, can
* be used for peeking ahead into the received data: the bytes are not removed
* from the stream during the read.
*/
class IIOStream
{
public:
/// I/O to the stream failed. @ingroup errors
DENG2_ERROR(IOError);

/// Only reading is allowed from the stream. @ingroup errors
DENG2_SUB_ERROR(IOError, ReadOnlyError);

public:
virtual ~IIOStream() {}

/**
* Writes an array of bytes to the stream.
*
* @param bytes Byte array to write.
*
* @return Reference to this IIOStream object.
*/
virtual IIOStream& operator << (const IByteArray& bytes) = 0;

/**
* Reads all the available bytes into the array @a bytes. If there is
* nothing available for reading, nothing is written to @a bytes. The
* stream operates as a modifiable object: once read, the bytes are
* considered to be removed from the stream.
*
* @param bytes Read bytes are stored here.
*
* @return Reference to this IIOStream object.
*/
virtual IIOStream& operator >> (IByteArray& bytes) = 0;

/**
* Reads all the available bytes into the array @a bytes. If there is
* nothing available for reading, nothing is written to @a bytes.
*
* Immutable streams can be used for peeking ahead into the received data.
* Here the stream operates as a const object: the read bytes are not
* removed from the stream, and a subsequent read will return the same
* bytes, plus any additional bytes that may have been produced in the
* meantime.
*
* @param bytes Read bytes are stored here.
*
* @return Reference to this IIOStream object.
*/
virtual const IIOStream& operator >> (IByteArray& bytes) const = 0;
};

} // namespace de

#endif // LIBDENG2_IIOSTREAM_H
69 changes: 45 additions & 24 deletions doomsday/libdeng2/include/de/data/reader.h
Expand Up @@ -30,6 +30,7 @@ class Block;
class String;
class IReadable;
class FixedByteArray;
class IIOStream;

/**
* Provides a protocol for reading data from a byte array object (anything with
Expand All @@ -40,17 +41,36 @@ class FixedByteArray;
*/
class DENG2_PUBLIC Reader
{
public:
/// Seeking is not possible, e.g., when reading from a stream. @ingroup errors
DENG2_ERROR(SeekError);

public:
/**
* Constructs a new reader.
*
* @param source Byte array containing the data to be read.
* @param byteOrder Byte order to use. The byte order defaults to network
* (big-endian) byte order.
* @param byteOrder Byte order to use.
* @param offset Offset in @a source where to start reading.
*/
Reader(const IByteArray& source, const ByteOrder& byteOrder = littleEndianByteOrder,
IByteArray::Offset offset = 0);
IByteArray::Offset offset = 0);

/**
* Constructs a new reader that reads from a stream.
*
* @param stream Stream where input is read.
* @param byteOrder Byte order to use.
*/
Reader(IIOStream& stream, const ByteOrder& byteOrder = littleEndianByteOrder);

/**
* Constructs a new reader that reads from a const stream.
*
* @param stream Const stream where input is read.
* @param byteOrder Byte order to use.
*/
Reader(const IIOStream& stream, const ByteOrder& byteOrder = littleEndianByteOrder);

//@{ Read a number from the source buffer, in network byte order.
Reader& operator >> (char& byte);
Expand Down Expand Up @@ -102,51 +122,52 @@ class DENG2_PUBLIC Reader
/**
* Returns the source byte array of the reader.
*/
const IByteArray& source() const {
return _source;
}
const IByteArray* source() const;

/**
* Returns the offset used by the reader.
*/
IByteArray::Offset offset() const {
return _offset;
}
IByteArray::Offset offset() const;

/**
* Move to a specific position in the source data.
*
* @param offset Offset to move to.
*/
void setOffset(IByteArray::Offset offset) {
_offset = offset;
}
void setOffset(IByteArray::Offset offset);

/**
* Moves the reader offset forward by a number of bytes.
* Moves the reader offset forward by a number of bytes. This is a random
* access seek: it is only possible if the source supports random access
* (e.g., it is impossible to seek in streams).
*
* @param count Number of bytes to move forward.
* @param count Number of bytes to move forward. Negative values move
* the reader offset backward.
*/
void seek(dint count);

/**
* Rewinds the read offset by a number of bytes.
*
* @param count Number of bytes to move backward.
* Marks the current position for rewinding later. After setting the mark,
* you are expected to call rewind() to return to the marked position. This
* method can be used even when reading from streams.
*/
void mark();

/**
* Rewinds the read offset to the mark set previously (using mark()).
* Rewinding can be done with all readers, regardless of where the data
* comes from.
*/
void rewind(dint count);
void rewind();

/**
* Returns the byte order of the writer.
*/
const ByteOrder& byteOrder() const {
return _convert;
}
const ByteOrder& byteOrder() const;

private:
const IByteArray& _source;
IByteArray::Offset _offset;
const ByteOrder& _convert;
struct Instance;
Instance* d;
};

} // namespace de
Expand Down

0 comments on commit e1e1d7c

Please sign in to comment.