forked from mirror/openmw-tes3mp
Added writing capability to streams. Created OutFileStream.
This commit is contained in:
parent
21d399cb81
commit
71366d9a07
12 changed files with 225 additions and 8 deletions
|
@ -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);
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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;
|
||||||
|
|
41
stream/servers/outfile_stream.hpp
Normal file
41
stream/servers/outfile_stream.hpp
Normal 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
|
79
stream/servers/std_ostream.hpp
Normal file
79
stream/servers/std_ostream.hpp
Normal 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
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
1
stream/tests/.gitignore
vendored
1
stream/tests/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
*_test
|
*_test
|
||||||
|
test.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 $@
|
||||||
|
|
||||||
|
|
41
stream/tests/file_write_test.cpp
Normal file
41
stream/tests/file_write_test.cpp
Normal 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;
|
||||||
|
}
|
12
stream/tests/output/file_write_test.out
Normal file
12
stream/tests/output/file_write_test.out
Normal 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
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue