Added writing capability to streams. Created OutFileStream.

This commit is contained in:
Nicolay Korslund 2010-08-04 12:20:46 +02:00
parent 21d399cb81
commit 71366d9a07
12 changed files with 225 additions and 8 deletions

View file

@ -23,6 +23,10 @@ class Mangle2OgreStream : public Ogre::DataStream
// Get the size, if possible // Get the size, if possible
if(inp->hasSize) if(inp->hasSize)
mSize = inp->size(); mSize = inp->size();
// Allow writing if inp supports it
if(inp->isWritable)
mAccess |= Ogre::DataStream::WRITE;
} }
public: public:
@ -39,6 +43,9 @@ class Mangle2OgreStream : public Ogre::DataStream
size_t read(void *buf, size_t count) size_t read(void *buf, size_t count)
{ return inp->read(buf,count); } { return inp->read(buf,count); }
size_t write(const void *buf, size_t count)
{ assert(inp->isWritable); return inp->write(buf,count); }
void skip(long count) void skip(long count)
{ {
assert(inp->isSeekable && inp->hasPosition); assert(inp->isSeekable && inp->hasPosition);

View file

@ -23,12 +23,14 @@ class PureFilter : public Stream
{ {
src = _src; src = _src;
isSeekable = src->isSeekable; isSeekable = src->isSeekable;
isWritable = src->isWritable;
hasPosition = src->hasPosition; hasPosition = src->hasPosition;
hasSize = src->hasSize; hasSize = src->hasSize;
hasPtr = src->hasPtr; hasPtr = src->hasPtr;
} }
size_t read(void *buf, size_t count) { return src->read(buf, count); } size_t read(void *buf, size_t count) { return src->read(buf, count); }
size_t write(const void *buf, size_t count) { return src->write(buf,count); }
void seek(size_t pos) { src->seek(pos); } void seek(size_t pos) { src->seek(pos); }
size_t tell() const { return src->tell(); } size_t tell() const { return src->tell(); }
size_t size() const { return src->size(); } size_t size() const { return src->size(); }

View file

@ -27,6 +27,7 @@ class SliceStream : public Stream
hasPosition = true; hasPosition = true;
hasSize = true; hasSize = true;
hasPtr = src->hasPtr; hasPtr = src->hasPtr;
isWritable = src->isWritable;
} }
size_t read(void *buf, size_t count) size_t read(void *buf, size_t count)
@ -35,7 +36,7 @@ class SliceStream : public Stream
if(count > length-pos) if(count > length-pos)
count = length-pos; count = length-pos;
// Seek into place and reading // Seek into place and start reading
src->seek(offset+pos); src->seek(offset+pos);
count = src->read(buf, count); count = src->read(buf, count);
@ -44,6 +45,24 @@ class SliceStream : public Stream
return count; return count;
} }
// Note that writing to a slice does not allow you to append data,
// you may only overwrite existing data.
size_t write(const void *buf, size_t count)
{
assert(isWritable);
// Check that we're not reading past our slice
if(count > length-pos)
count = length-pos;
// Seek into place and action
src->seek(offset+pos);
count = src->write(buf, count);
pos += count;
assert(pos <= length);
return count;
}
void seek(size_t _pos) void seek(size_t _pos)
{ {
pos = _pos; pos = _pos;

View file

@ -0,0 +1,41 @@
#ifndef MANGLE_STREAM_FILESERVER_H
#define MANGLE_STREAM_FILESERVER_H
#include "std_ostream.hpp"
#include <fstream>
namespace Mangle {
namespace Stream {
/** File stream based on std::ofstream, only supports writing.
*/
class OutFileStream : public StdOStream
{
std::ofstream file;
public:
/**
By default we overwrite the file. If append=true, then we will
open an existing file and seek to the end instead.
*/
OutFileStream(const std::string &name, bool append=false)
: StdOStream(&file)
{
std::ios::openmode mode = std::ios::binary;
if(append)
mode |= std::ios::app;
else
mode |= std::ios::trunc;
file.open(name.c_str(), mode);
if(file.fail())
throw str_exception("OutFileStream: failed to open file " + name);
}
~OutFileStream() { file.close(); }
};
typedef boost::shared_ptr<OutFileStream> OutFileStreamPtr;
}} // namespaces
#endif

View file

@ -0,0 +1,79 @@
#ifndef MANGLE_STREAM_STDIOSERVER_H
#define MANGLE_STREAM_STDIOSERVER_H
#include "../stream.hpp"
#include <iostream>
#include "../../tools/str_exception.hpp"
namespace Mangle {
namespace Stream {
/** Simple wrapper for std::ostream, only supports output.
*/
class StdOStream : public Stream
{
std::ostream *inf;
static void fail(const std::string &msg)
{ throw str_exception("StdOStream: " + msg); }
public:
StdOStream(std::ostream *_inf)
: inf(_inf)
{
isSeekable = true;
hasPosition = true;
hasSize = true;
isWritable = true;
}
size_t read(void*,size_t)
{
assert(0&&"reading not supported by StdOStream");
}
size_t write(const void* buf, size_t len)
{
inf->write((const char*)buf, len);
if(inf->fail())
fail("error writing to stream");
// Unfortunately, stupid std::ostream doesn't have a pcount() to
// match gcount() for input. In general the std::iostream system
// is an idiotically designed stream library.
return len;
}
void seek(size_t pos)
{
inf->seekp(pos);
if(inf->fail())
fail("seek error");
}
size_t tell() const
// Hack around the fact that ifstream->tellp() isn't const
{ return ((StdOStream*)this)->inf->tellp(); }
size_t size() const
{
// Use the standard iostream size hack, terrible as it is.
std::streampos pos = inf->tellp();
inf->seekp(0, std::ios::end);
size_t res = inf->tellp();
inf->seekp(pos);
if(inf->fail())
fail("could not get stream size");
return res;
}
bool eof() const
{ return inf->eof(); }
};
typedef boost::shared_ptr<StdOStream> StdOStreamPtr;
}} // namespaces
#endif

View file

@ -8,7 +8,7 @@
namespace Mangle { namespace Mangle {
namespace Stream { namespace Stream {
/** Simplest wrapper for std::istream. /** Simple wrapper for std::istream.
*/ */
class StdStream : public Stream class StdStream : public Stream
{ {

View file

@ -23,13 +23,17 @@ class Stream
/// If true, size() works /// If true, size() works
bool hasSize; bool hasSize;
/// If true, write() works. Writing through pointer operations is
/// not supported.
bool isWritable;
/// If true, the getPtr() functions work /// If true, the getPtr() functions work
bool hasPtr; bool hasPtr;
/// Initialize all bools to false by default /// Initialize all bools to false by default
Stream() : Stream() :
isSeekable(false), hasPosition(false), hasSize(false), isSeekable(false), hasPosition(false), hasSize(false),
hasPtr(false) {} isWritable(false), hasPtr(false) {}
/// Virtual destructor /// Virtual destructor
virtual ~Stream() {} virtual ~Stream() {}
@ -40,6 +44,14 @@ class Stream
*/ */
virtual size_t read(void* buf, size_t count) = 0; virtual size_t read(void* buf, size_t count) = 0;
/** Write a given number of bytes from the stream. Semantics is
similar to read(). Only valid if isWritable is true
Since most implementations do NOT support writing we default to
an assert(0) here.
*/
virtual size_t write(const void *buf, size_t count) { assert(0); return 0; }
/// Seek to an absolute position in this stream. Not all streams are /// Seek to an absolute position in this stream. Not all streams are
/// seekable. /// seekable.
virtual void seek(size_t pos) = 0; virtual void seek(size_t pos) = 0;

View file

@ -1 +1,2 @@
*_test *_test
test.file

View file

@ -1,6 +1,6 @@
GCC=g++ -I../ GCC=g++ -I../
all: ogre_client_test audiere_client_test memory_server_test buffer_filter_test file_server_test slice_filter_test all: ogre_client_test audiere_client_test memory_server_test buffer_filter_test file_server_test slice_filter_test file_write_test
I_OGRE=$(shell pkg-config --cflags OGRE) I_OGRE=$(shell pkg-config --cflags OGRE)
L_OGRE=$(shell pkg-config --libs OGRE) L_OGRE=$(shell pkg-config --libs OGRE)
@ -15,6 +15,9 @@ audiere_client_test: audiere_client_test.cpp ../stream.hpp ../clients/audiere_fi
file_server_test: file_server_test.cpp ../stream.hpp ../servers/file_stream.hpp ../servers/std_stream.hpp file_server_test: file_server_test.cpp ../stream.hpp ../servers/file_stream.hpp ../servers/std_stream.hpp
$(GCC) $< -o $@ $(GCC) $< -o $@
file_write_test: file_write_test.cpp ../stream.hpp ../servers/outfile_stream.hpp ../servers/std_ostream.hpp
$(GCC) $< -o $@
memory_server_test: memory_server_test.cpp ../stream.hpp ../servers/memory_stream.hpp memory_server_test: memory_server_test.cpp ../stream.hpp ../servers/memory_stream.hpp
$(GCC) $< -o $@ $(GCC) $< -o $@

View file

@ -0,0 +1,41 @@
#include "../servers/outfile_stream.hpp"
#include <iostream>
using namespace Mangle::Stream;
using namespace std;
void print(Stream &str)
{
cout << "size=" << str.size()
<< " pos=" << str.tell()
<< " eof=" << str.eof()
<< endl;
}
int main()
{
{
cout << "\nCreating file\n";
OutFileStream out("test.file");
print(out);
out.write("hello",5);
print(out);
}
{
cout << "\nAppending to file\n";
OutFileStream out("test.file", true);
print(out);
out.write(" again\n",7);
print(out);
}
{
cout << "\nOverwriting file\n";
OutFileStream out("test.file");
print(out);
out.write("overwrite!\n",11);
print(out);
}
return 0;
}

View file

@ -0,0 +1,12 @@
Creating file
size=0 pos=0 eof=0
size=5 pos=5 eof=0
Appending to file
size=5 pos=5 eof=0
size=12 pos=12 eof=0
Overwriting file
size=0 pos=0 eof=0
size=11 pos=11 eof=0

View file

@ -11,9 +11,9 @@ namespace VFS {
/** An OGRE Archive implementation that wraps a Mangle::VFS /** An OGRE Archive implementation that wraps a Mangle::VFS
filesystem. filesystem.
This has been built and tested against OGRE 1.6.2. You might have This has been built and tested against OGRE 1.6.2, and has been
to make your own modifications if you're working with newer (or extended for OGRE 1.7. You might have to make your own
older) versions. modifications if you're working with newer (or older) versions.
*/ */
class MangleArchive : public Ogre::Archive class MangleArchive : public Ogre::Archive
{ {