From bbb44e07bfa1d3cb2161ee4e1c2156ca135d2f45 Mon Sep 17 00:00:00 2001 From: Nicolay Korslund Date: Sat, 19 Dec 2009 20:53:53 +0100 Subject: [PATCH] Added VFS+tests, make Ogre::Archive client implementation. --- Doxyfile | 2 +- stream/tests/dummy_input.cpp | 2 +- vfs/imp_client/ogre_archive.cpp | 83 +++++++++++++++++++++++ vfs/imp_client/ogre_archive.h | 53 +++++++++++++++ vfs/imp_client/wrapper.h | 30 +++++++++ vfs/tests/.gitignore | 1 + vfs/tests/Makefile | 15 +++++ vfs/tests/dummy_test.cpp | 40 +++++++++++ vfs/tests/dummy_vfs.cpp | 115 ++++++++++++++++++++++++++++++++ vfs/tests/ogre_client_test.cpp | 39 +++++++++++ vfs/vfs.h | 79 ++++++++++++++++++++++ 11 files changed, 457 insertions(+), 2 deletions(-) create mode 100644 vfs/imp_client/ogre_archive.cpp create mode 100644 vfs/imp_client/ogre_archive.h create mode 100644 vfs/imp_client/wrapper.h create mode 100644 vfs/tests/.gitignore create mode 100644 vfs/tests/Makefile create mode 100644 vfs/tests/dummy_test.cpp create mode 100644 vfs/tests/dummy_vfs.cpp create mode 100644 vfs/tests/ogre_client_test.cpp create mode 100644 vfs/vfs.h diff --git a/Doxyfile b/Doxyfile index 705b0aa321..f2a1c74552 100644 --- a/Doxyfile +++ b/Doxyfile @@ -564,7 +564,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = sound +INPUT = sound stream vfs # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff --git a/stream/tests/dummy_input.cpp b/stream/tests/dummy_input.cpp index 4625540ec3..0bfe5ad52a 100644 --- a/stream/tests/dummy_input.cpp +++ b/stream/tests/dummy_input.cpp @@ -1,5 +1,5 @@ // This file is shared between several test programs -#include "input.h" +#include "../input.h" #include #include diff --git a/vfs/imp_client/ogre_archive.cpp b/vfs/imp_client/ogre_archive.cpp new file mode 100644 index 0000000000..c9dccab902 --- /dev/null +++ b/vfs/imp_client/ogre_archive.cpp @@ -0,0 +1,83 @@ +#include "ogre_archive.h" + +#include "../../stream/imp_client/ogre_datastream.h" + +using namespace Mangle::VFS; +using namespace Mangle::Stream; + +Ogre::DataStreamPtr MangleArchive::open(const Ogre::String& filename) const +{ + return Ogre::DataStreamPtr(new MangleDataStream + (filename, vfs->open(filename), true)); +} + +static void fill(Ogre::FileInfoList &out, FileInfoList &in) +{ + int size = in.size(); + out.resize(size); + + for(int i=0; ilist("", recursive, dirs); + Ogre::StringVector *res = new Ogre::StringVector; + + fill(*res, lst); + + return Ogre::StringVectorPtr(res); +} + +Ogre::FileInfoListPtr MangleArchive::listFileInfo(bool recursive, bool dirs) +{ + FileInfoList lst = vfs->list("", recursive, dirs); + Ogre::FileInfoList *res = new Ogre::FileInfoList; + + fill(*res, lst); + + return Ogre::FileInfoListPtr(res); +} + +// Find functions will only work if vfs->hasFind is set. +Ogre::StringVectorPtr MangleArchive::find(const Ogre::String& pattern, + bool recursive, + bool dirs) +{ + assert(vfs->hasFind); + FileInfoList lst = vfs->find(pattern, recursive, dirs); + Ogre::StringVector *res = new Ogre::StringVector; + + fill(*res, lst); + + return Ogre::StringVectorPtr(res); +} + +Ogre::FileInfoListPtr MangleArchive::findFileInfo(const Ogre::String& pattern, + bool recursive, + bool dirs) +{ + assert(vfs->hasFind); + FileInfoList lst = vfs->find(pattern, recursive, dirs); + Ogre::FileInfoList *res = new Ogre::FileInfoList; + + fill(*res, lst); + + return Ogre::FileInfoListPtr(res); +} diff --git a/vfs/imp_client/ogre_archive.h b/vfs/imp_client/ogre_archive.h new file mode 100644 index 0000000000..f72398a2de --- /dev/null +++ b/vfs/imp_client/ogre_archive.h @@ -0,0 +1,53 @@ +#ifndef MANGLE_VFS_OGRECLIENT_H +#define MANGLE_VFS_OGRECLIENT_H + +#include +#include +#include "wrapper.h" + +namespace Mangle { +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. + */ +class MangleArchive : public Ogre::Archive, _Wrapper +{ + public: + /// Constructor without name + MangleArchive(VFS *vfs, const std::string &name, + const std::string &archType = "Mangle", + bool autoDel=false) + : _Wrapper(vfs, autoDel), Ogre::Archive(name, archType) {} + + bool isCaseSensitive() const { return vfs->isCaseSensitive; } + + // These do nothing. You have to load / unload the archive manually. + void load() {} + void unload() {} + + bool exists(const Ogre::String& filename) + { return vfs->isFile(filename); } + + time_t getModifiedTime(const Ogre::String& filename) + { return vfs->stat(filename).time; } + + Ogre::DataStreamPtr open(const Ogre::String& filename) const; + + Ogre::StringVectorPtr list(bool recursive = true, bool dirs = false); + Ogre::FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false); + + // Find functions will only work if vfs->hasFind is set. + Ogre::StringVectorPtr find(const Ogre::String& pattern, bool recursive = true, + bool dirs = false); + Ogre::FileInfoListPtr findFileInfo(const Ogre::String& pattern, + bool recursive = true, + bool dirs = false); +}; + +}} // namespaces +#endif diff --git a/vfs/imp_client/wrapper.h b/vfs/imp_client/wrapper.h new file mode 100644 index 0000000000..357bc8b4f4 --- /dev/null +++ b/vfs/imp_client/wrapper.h @@ -0,0 +1,30 @@ +#ifndef MANGLE_VFS_WRAPPER_H +#define MANGLE_VFS_WRAPPER_H + +#include "../vfs.h" +#include + +namespace Mangle { +namespace VFS { + +/** A generic wrapper class for a VFS::VFS object. + + This is used by other implementations. + */ +class _Wrapper +{ + private: + bool autoDel; + + protected: + VFS *vfs; + + public: + _Wrapper(VFS *_vfs, bool _autoDel = false) + : vfs(_vfs), autoDel(_autoDel) { assert(vfs != NULL); } + + virtual ~_Wrapper() { if(autoDel) delete vfs; } +}; + +}} // namespaces +#endif diff --git a/vfs/tests/.gitignore b/vfs/tests/.gitignore new file mode 100644 index 0000000000..8144904045 --- /dev/null +++ b/vfs/tests/.gitignore @@ -0,0 +1 @@ +*_test diff --git a/vfs/tests/Makefile b/vfs/tests/Makefile new file mode 100644 index 0000000000..b1fb55f13d --- /dev/null +++ b/vfs/tests/Makefile @@ -0,0 +1,15 @@ +GCC=g++ -I../ -I../imp_client/ + +all: dummy_test ogre_client_test + +I_OGRE=$(shell pkg-config --cflags OGRE) +L_OGRE=$(shell pkg-config --libs OGRE) + +ogre_client_test: ogre_client_test.cpp dummy_vfs.cpp ../vfs.h ../imp_client/wrapper.h ../imp_client/ogre_archive.h ../imp_client/ogre_archive.cpp + $(GCC) $< ../imp_client/ogre_archive.cpp -o $@ $(I_OGRE) $(L_OGRE) + +dummy_test: dummy_test.cpp dummy_vfs.cpp ../vfs.h + $(GCC) $< -o $@ + +clean: + rm *_test diff --git a/vfs/tests/dummy_test.cpp b/vfs/tests/dummy_test.cpp new file mode 100644 index 0000000000..e5659d62f6 --- /dev/null +++ b/vfs/tests/dummy_test.cpp @@ -0,0 +1,40 @@ +#include "dummy_vfs.cpp" + +#include +#include + +using namespace std; + +void print(FileInfo inf) +{ + cout << "name: " << inf.name << endl; + cout << "basename: " << inf.basename << endl; + cout << "isDir: " << inf.isDir << endl; + cout << "size: " << inf.size << endl; + cout << "time: " << inf.time << endl; +} + +void print(FileInfoList lst) +{ + for(int i=0; isize() << endl; + + return 0; +} diff --git a/vfs/tests/dummy_vfs.cpp b/vfs/tests/dummy_vfs.cpp new file mode 100644 index 0000000000..d8b259f28b --- /dev/null +++ b/vfs/tests/dummy_vfs.cpp @@ -0,0 +1,115 @@ +// This file is shared between several test programs +#include "vfs.h" +#include +#include + +#include "../../stream/tests/dummy_input.cpp" + +using namespace Mangle::VFS; + +class DummyVFS : public VFS +{ +public: + DummyVFS() + { + hasFind = false; + isCaseSensitive = true; + } + + // We only support opening 'file1' at the moment. + Mangle::Stream::InputStream *open(const std::string &name) + { + assert(name == "file1"); + return new DummyInput(); + } + + bool isFile(const std::string &name) const + { + return (name == "file1" || + name == "dir/file2"); + } + + bool isDir(const std::string &name) const + { + return name == "dir"; + } + + /// Get info about a single file + FileInfo stat(const std::string &name) const + { + FileInfo fi; + fi.name = name; + fi.time = 0; + + if(isFile(name)) + { + if(name == "dir/file2") + { + fi.basename = "file2"; + fi.size = 2; + } + else + { + fi.basename = "file1"; + fi.size = 1; + } + fi.isDir = false; + } + else if(isDir(name)) + { + fi.basename = "dir"; + fi.isDir = true; + fi.size = 0; + } + else assert(0); + + return fi; + } + + /// List all entries in a given directory. A blank dir should be + /// interpreted as a the root/current directory of the archive. If + /// dirs is true, list directories instead of files. + virtual FileInfoList list(const std::string& dir = "", + bool recurse=true, + bool dirs=false) const + { + assert(dir == ""); + + FileInfoList fl; + + FileInfo fi; + + if(!dirs) + { + fi.name = "file1"; + fi.basename = "file1"; + fi.isDir = false; + fi.size = 1; + fi.time = 0; + fl.push_back(fi); + + if(recurse) + { + fi.name = "dir/file2"; + fi.basename = "file2"; + fi.size = 2; + fl.push_back(fi); + } + } + else + { + fi.name = "dir"; + fi.basename = "dir"; + fi.isDir = true; + fi.size = 0; + fi.time = 0; + fl.push_back(fi); + } + return fl; + } + + FileInfoList find(const std::string& pattern, + bool recursive=true, + bool dirs=false) const + { assert(0); return FileInfoList(); } +}; diff --git a/vfs/tests/ogre_client_test.cpp b/vfs/tests/ogre_client_test.cpp new file mode 100644 index 0000000000..92cb73eaa8 --- /dev/null +++ b/vfs/tests/ogre_client_test.cpp @@ -0,0 +1,39 @@ +#include "dummy_vfs.cpp" +#include "ogre_archive.h" +#include + +using namespace Ogre; +using namespace std; + +void print(StringVectorPtr lst) +{ + int s = lst->size(); + + for(int i=0; isize() << endl; + cout << "contents: " << file->getAsString() << endl; + + return 0; +} diff --git a/vfs/vfs.h b/vfs/vfs.h new file mode 100644 index 0000000000..345b4ccaef --- /dev/null +++ b/vfs/vfs.h @@ -0,0 +1,79 @@ +#ifndef MANGLE_VFS_H +#define MANGLE_VFS_H + +#include "../stream/input.h" +#include +#include + +namespace Mangle { +namespace VFS { + +/// Generic file info structure +struct FileInfo +{ + /// Full name, including path + std::string name; + + /// Base name, not including path + std::string basename; + + /// Is this a directory? + bool isDir; + + /// File size + size_t size; + + /// Last modification date + time_t time; +}; + +typedef std::vector FileInfoList; + +/** An interface to any file system or other provider of named data + streams +*/ +class VFS +{ + public: + // Feature options. These should be set in the constructor. + + /// If true, the find*() functions work + bool hasFind; + + /// If true, the file system is case sensitive + bool isCaseSensitive; + + /// Virtual destructor + virtual ~VFS() {} + + /// Open a new data stream. Deleting the object should be enough to + /// close it. + virtual Stream::InputStream *open(const std::string &name) = 0; + + /// Check for the existence of a file + virtual bool isFile(const std::string &name) const = 0; + + /// Check for the existence of a directory + virtual bool isDir(const std::string &name) const = 0; + + /// Get info about a single file + virtual FileInfo stat(const std::string &name) const = 0; + + /// List all entries in a given directory. A blank dir should be + /// interpreted as a the root/current directory of the archive. If + /// dirs is true, list directories instead of files. + virtual FileInfoList list(const std::string& dir = "", + bool recurse=true, + bool dirs=false) const = 0; + + /// Find files after a given pattern. Wildcards (*) are + /// supported. Only valid if 'hasFind' is true. Don't implement your + /// own pattern matching here if the backend doesn't support it + /// natively; use a filter instead. + virtual FileInfoList find(const std::string& pattern, + bool recursive=true, + bool dirs=false) const = 0; +}; + +}} // namespaces +#endif