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
if(inp->hasSize)
mSize = inp->size();
// Allow writing if inp supports it
if(inp->isWritable)
mAccess |= Ogre::DataStream::WRITE;
}
public:
@ -37,7 +41,10 @@ class Mangle2OgreStream : public Ogre::DataStream
// Only implement the DataStream functions we have to implement
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)
{

View file

@ -23,12 +23,14 @@ class PureFilter : public Stream
{
src = _src;
isSeekable = src->isSeekable;
isWritable = src->isWritable;
hasPosition = src->hasPosition;
hasSize = src->hasSize;
hasPtr = src->hasPtr;
}
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); }
size_t tell() const { return src->tell(); }
size_t size() const { return src->size(); }

View file

@ -27,6 +27,7 @@ class SliceStream : public Stream
hasPosition = true;
hasSize = true;
hasPtr = src->hasPtr;
isWritable = src->isWritable;
}
size_t read(void *buf, size_t count)
@ -35,7 +36,7 @@ class SliceStream : public Stream
if(count > length-pos)
count = length-pos;
// Seek into place and reading
// Seek into place and start reading
src->seek(offset+pos);
count = src->read(buf, count);
@ -44,6 +45,24 @@ class SliceStream : public Stream
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)
{
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 Stream {
/** Simplest wrapper for std::istream.
/** Simple wrapper for std::istream.
*/
class StdStream : public Stream
{

View file

@ -23,13 +23,17 @@ class Stream
/// If true, size() works
bool hasSize;
/// If true, write() works. Writing through pointer operations is
/// not supported.
bool isWritable;
/// If true, the getPtr() functions work
bool hasPtr;
/// Initialize all bools to false by default
Stream() :
isSeekable(false), hasPosition(false), hasSize(false),
hasPtr(false) {}
isWritable(false), hasPtr(false) {}
/// Virtual destructor
virtual ~Stream() {}
@ -40,6 +44,14 @@ class Stream
*/
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
/// seekable.
virtual void seek(size_t pos) = 0;

View file

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

View file

@ -1,6 +1,6 @@
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)
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
$(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
$(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
filesystem.
This has been built and tested against OGRE 1.6.2. You might have
to make your own modifications if you're working with newer (or
older) versions.
This has been built and tested against OGRE 1.6.2, and has been
extended for OGRE 1.7. You might have to make your own
modifications if you're working with newer (or older) versions.
*/
class MangleArchive : public Ogre::Archive
{