Rename the ResourceProxy class to EmbeddedResourceProxy

This is done so as to avoid confusion with the unrelated classes
ResourceProvider and ResourceManager already present in SimGear.

Despite this new name, EmbeddedResourceProxy is a proxy not only for
embedded resources, but also for real files (hence the initial name
choice): its purpose is precisely to allow zero-work switching from one
data source to the other.
This commit is contained in:
Florent Rougon
2017-10-07 16:36:49 +02:00
parent e5e112c3c2
commit 2200fad30e
4 changed files with 107 additions and 86 deletions
+6 -2
View File
@@ -1,7 +1,11 @@
include (SimGearComponent) include (SimGearComponent)
set(HEADERS EmbeddedResource.hxx EmbeddedResourceManager.hxx ResourceProxy.hxx) set(HEADERS EmbeddedResource.hxx
set(SOURCES EmbeddedResource.cxx EmbeddedResourceManager.cxx ResourceProxy.cxx) EmbeddedResourceManager.hxx
EmbeddedResourceProxy.hxx)
set(SOURCES EmbeddedResource.cxx
EmbeddedResourceManager.cxx
EmbeddedResourceProxy.cxx)
simgear_component(embedded_resources embedded_resources simgear_component(embedded_resources embedded_resources
"${SOURCES}" "${HEADERS}") "${SOURCES}" "${HEADERS}")
@@ -1,6 +1,7 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// //
// ResourceProxy.cxx --- Unified access to real files or embedded resources // EmbeddedResourceProxy.cxx --- Unified access to real files or embedded
// resources
// Copyright (C) 2017 Florent Rougon // Copyright (C) 2017 Florent Rougon
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
@@ -35,7 +36,7 @@
#include <simgear/io/iostreams/sgstream.hxx> #include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include "EmbeddedResourceManager.hxx" #include "EmbeddedResourceManager.hxx"
#include "ResourceProxy.hxx" #include "EmbeddedResourceProxy.hxx"
using std::string; using std::string;
using std::vector; using std::vector;
@@ -46,35 +47,36 @@ using std::unique_ptr;
namespace simgear namespace simgear
{ {
ResourceProxy::ResourceProxy(const SGPath& realRoot, const string& virtualRoot, EmbeddedResourceProxy::EmbeddedResourceProxy(const SGPath& realRoot,
bool useEmbeddedResourcesByDefault) const string& virtualRoot,
bool useEmbeddedResourcesByDefault)
: _realRoot(realRoot), : _realRoot(realRoot),
_virtualRoot(normalizeVirtualRoot(virtualRoot)), _virtualRoot(normalizeVirtualRoot(virtualRoot)),
_useEmbeddedResourcesByDefault(useEmbeddedResourcesByDefault) _useEmbeddedResourcesByDefault(useEmbeddedResourcesByDefault)
{ } { }
SGPath SGPath
ResourceProxy::getRealRoot() const EmbeddedResourceProxy::getRealRoot() const
{ return _realRoot; } { return _realRoot; }
void void
ResourceProxy::setRealRoot(const SGPath& realRoot) EmbeddedResourceProxy::setRealRoot(const SGPath& realRoot)
{ _realRoot = realRoot; } { _realRoot = realRoot; }
string string
ResourceProxy::getVirtualRoot() const EmbeddedResourceProxy::getVirtualRoot() const
{ return _virtualRoot; } { return _virtualRoot; }
void void
ResourceProxy::setVirtualRoot(const string& virtualRoot) EmbeddedResourceProxy::setVirtualRoot(const string& virtualRoot)
{ _virtualRoot = normalizeVirtualRoot(virtualRoot); } { _virtualRoot = normalizeVirtualRoot(virtualRoot); }
bool bool
ResourceProxy::getUseEmbeddedResources() const EmbeddedResourceProxy::getUseEmbeddedResources() const
{ return _useEmbeddedResourcesByDefault; } { return _useEmbeddedResourcesByDefault; }
void void
ResourceProxy::setUseEmbeddedResources(bool useEmbeddedResources) EmbeddedResourceProxy::setUseEmbeddedResources(bool useEmbeddedResources)
{ _useEmbeddedResourcesByDefault = useEmbeddedResources; } { _useEmbeddedResourcesByDefault = useEmbeddedResources; }
// Static method: normalize the 'virtualRoot' argument of the constructor // Static method: normalize the 'virtualRoot' argument of the constructor
@@ -82,9 +84,10 @@ ResourceProxy::setUseEmbeddedResources(bool useEmbeddedResources)
// The argument must start with a slash and mustn't contain any '.' or '..' // The argument must start with a slash and mustn't contain any '.' or '..'
// component. The return value never ends with a slash. // component. The return value never ends with a slash.
string string
ResourceProxy::normalizeVirtualRoot(const string& path) EmbeddedResourceProxy::normalizeVirtualRoot(const string& path)
{ {
ResourceProxy::checkPath(__func__, path, false /* allowStartWithColon */); EmbeddedResourceProxy::checkPath(__func__, path,
false /* allowStartWithColon */);
string res = path; string res = path;
// Make sure 'res' doesn't end with a '/'. // Make sure 'res' doesn't end with a '/'.
@@ -97,21 +100,22 @@ ResourceProxy::normalizeVirtualRoot(const string& path)
// Static method // Static method
void void
ResourceProxy::checkPath(const string& callerMethod, const string& path, EmbeddedResourceProxy::checkPath(const string& callerMethod, const string& path,
bool allowStartWithColon) { bool allowStartWithColon)
{
if (path.empty()) { if (path.empty()) {
throw sg_format_exception( throw sg_format_exception(
"Invalid empty path for ResourceProxy::" + callerMethod + "(): '" + "Invalid empty path for EmbeddedResourceProxy::" +
path + "'", path); callerMethod + "(): '" + path + "'", path);
} else if (allowStartWithColon && } else if (allowStartWithColon &&
!simgear::strutils::starts_with(path, ":/") && path[0] != '/') { !simgear::strutils::starts_with(path, ":/") && path[0] != '/') {
throw sg_format_exception( throw sg_format_exception(
"Invalid path for ResourceProxy::" + callerMethod + "(): it should " "Invalid path for EmbeddedResourceProxy::" + callerMethod + "(): "
"start with either ':/' or '/'", path); "it should start with either ':/' or '/'", path);
} else if (!allowStartWithColon && path[0] != '/') { } else if (!allowStartWithColon && path[0] != '/') {
throw sg_format_exception( throw sg_format_exception(
"Invalid path for ResourceProxy::" + callerMethod + "(): it should " "Invalid path for EmbeddedResourceProxy::" + callerMethod + "(): "
"start with a slash ('/')", path); "it should start with a slash ('/')", path);
} else { } else {
const vector<string> components = simgear::strutils::split(path, "/"); const vector<string> components = simgear::strutils::split(path, "/");
auto find = [&components](const string& s) -> bool { auto find = [&components](const string& s) -> bool {
@@ -121,16 +125,18 @@ ResourceProxy::checkPath(const string& callerMethod, const string& path,
if (find(".") || find("..")) { if (find(".") || find("..")) {
throw sg_format_exception( throw sg_format_exception(
"Invalid path for ResourceProxy::" + callerMethod + "(): " "Invalid path for EmbeddedResourceProxy::" + callerMethod + "(): "
"'.' and '..' components are not allowed", path); "'.' and '..' components are not allowed", path);
} }
} }
} }
unique_ptr<std::istream> unique_ptr<std::istream>
ResourceProxy::getIStream(const string& path, bool fromEmbeddedResource) const EmbeddedResourceProxy::getIStream(const string& path, bool fromEmbeddedResource)
const
{ {
ResourceProxy::checkPath(__func__, path, false /* allowStartWithColon */); EmbeddedResourceProxy::checkPath(__func__, path,
false /* allowStartWithColon */);
assert(!path.empty() && path.front() == '/'); assert(!path.empty() && path.front() == '/');
if (fromEmbeddedResource) { if (fromEmbeddedResource) {
@@ -145,15 +151,16 @@ ResourceProxy::getIStream(const string& path, bool fromEmbeddedResource) const
} }
unique_ptr<std::istream> unique_ptr<std::istream>
ResourceProxy::getIStream(const string& path) const EmbeddedResourceProxy::getIStream(const string& path) const
{ {
return getIStream(path, _useEmbeddedResourcesByDefault); return getIStream(path, _useEmbeddedResourcesByDefault);
} }
unique_ptr<std::istream> unique_ptr<std::istream>
ResourceProxy::getIStreamDecideOnPrefix(const string& path) const EmbeddedResourceProxy::getIStreamDecideOnPrefix(const string& path) const
{ {
ResourceProxy::checkPath(__func__, path, true /* allowStartWithColon */); EmbeddedResourceProxy::checkPath(__func__, path,
true /* allowStartWithColon */);
// 'path' is non-empty // 'path' is non-empty
if (path.front() == '/') { if (path.front() == '/') {
@@ -170,11 +177,13 @@ ResourceProxy::getIStreamDecideOnPrefix(const string& path) const
} }
string string
ResourceProxy::getString(const string& path, bool fromEmbeddedResource) const EmbeddedResourceProxy::getString(const string& path, bool fromEmbeddedResource)
const
{ {
string result; string result;
ResourceProxy::checkPath(__func__, path, false /* allowStartWithColon */); EmbeddedResourceProxy::checkPath(__func__, path,
false /* allowStartWithColon */);
assert(!path.empty() && path.front() == '/'); assert(!path.empty() && path.front() == '/');
if (fromEmbeddedResource) { if (fromEmbeddedResource) {
@@ -216,17 +225,18 @@ ResourceProxy::getString(const string& path, bool fromEmbeddedResource) const
} }
string string
ResourceProxy::getString(const string& path) const EmbeddedResourceProxy::getString(const string& path) const
{ {
return getString(path, _useEmbeddedResourcesByDefault); return getString(path, _useEmbeddedResourcesByDefault);
} }
string string
ResourceProxy::getStringDecideOnPrefix(const string& path) const EmbeddedResourceProxy::getStringDecideOnPrefix(const string& path) const
{ {
string result; string result;
ResourceProxy::checkPath(__func__, path, true /* allowStartWithColon */); EmbeddedResourceProxy::checkPath(__func__, path,
true /* allowStartWithColon */);
// 'path' is non-empty // 'path' is non-empty
if (path.front() == '/') { if (path.front() == '/') {
@@ -1,6 +1,7 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// //
// ResourceProxy.hxx --- Unified access to real files or embedded resources // EmbeddedResourceProxy.hxx --- Unified access to real files or embedded
// resources
// Copyright (C) 2017 Florent Rougon // Copyright (C) 2017 Florent Rougon
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
@@ -18,8 +19,8 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA. // MA 02110-1301 USA.
#ifndef FG_RESOURCEPROXY_HXX #ifndef FG_EMBEDDEDRESOURCEPROXY_HXX
#define FG_RESOURCEPROXY_HXX #define FG_EMBEDDEDRESOURCEPROXY_HXX
#include <istream> #include <istream>
#include <memory> #include <memory>
@@ -27,26 +28,27 @@
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
// The ResourceProxy class allows one to access real files or embedded // The EmbeddedResourceProxy class allows one to access real files or embedded
// resources in a unified way. When using it, one can switch from one data // resources in a unified way. When using it, one can switch from one data
// source to the other with minimal code changes, possibly even at runtime (in // source to the other with minimal code changes, possibly even at runtime (in
// which case there is obviously no code change at all). // which case there is obviously no code change at all).
// //
// Sample usage of the ResourceProxy class (from FlightGear): // Sample usage of the EmbeddedResourceProxy class (from FlightGear):
// //
// simgear::ResourceProxy proxy(globals->get_fg_root(), "/FGData"); // simgear::EmbeddedResourceProxy proxy(globals->get_fg_root(), "/FGData");
// std::string s = proxy.getString("/some/path"); // std::string s = proxy.getString("/some/path");
// std::unique_ptr<std::istream> streamp = proxy.getIStream("/some/path"); // std::unique_ptr<std::istream> streamp = proxy.getIStream("/some/path");
// //
// The methods ResourceProxy::getString(const std::string& path) and // The methods getString(const std::string& path) and
// ResourceProxy::getIStream(const std::string& path) decide whether to use // getIStream(const std::string& path) of EmbeddedResourceProxy decide whether
// embedded resources or real files depending on the boolean value passed to // to use embedded resources or real files depending on the boolean value
// ResourceProxy::setUseEmbeddedResources() (also available as an optional // passed to EmbeddedResourceProxy::setUseEmbeddedResources() (also available
// parameter to the ResourceProxy constructor, defaulting to true). It is // as an optional parameter to the EmbeddedResourceProxy constructor,
// often most convenient to set this boolean once and then don't worry about // defaulting to true). It is often most convenient to set this boolean once
// it anymore (it is stored inside ResourceProxy). Otherwise, if you want to // and then don't worry about it anymore (it is stored as a data member of
// fetch resources some times from real files, other times from embedded // EmbeddedResourceProxy). Otherwise, if you want to fetch resources some
// resources, you may use the following methods: // times from real files, other times from embedded resources, you may use the
// following methods:
// //
// // Retrieve contents using embedded resources // // Retrieve contents using embedded resources
// std:string s = proxy.getString("/some/path", true); // std:string s = proxy.getString("/some/path", true);
@@ -56,8 +58,8 @@
// std:string s = proxy.getString("/some/path", false); // std:string s = proxy.getString("/some/path", false);
// std:string s = proxy.getStringDecideOnPrefix("/some/path"); // std:string s = proxy.getStringDecideOnPrefix("/some/path");
// //
// You can do exactly the same with ResourceProxy::getIStream() and // You can do exactly the same with EmbeddedResourceProxy::getIStream() and
// ResourceProxy::getIStreamDecideOnPrefix(), except they return an // EmbeddedResourceProxy::getIStreamDecideOnPrefix(), except they return an
// std::unique_ptr<std::istream> instead of an std::string. // std::unique_ptr<std::istream> instead of an std::string.
// //
// Given how the 'proxy' object was constructed above, each of these calls // Given how the 'proxy' object was constructed above, each of these calls
@@ -65,8 +67,9 @@
// embedded resource whose virtual path is '/FGData/some/path' (more // embedded resource whose virtual path is '/FGData/some/path' (more
// precisely: the default-locale version of this resource). // precisely: the default-locale version of this resource).
// //
// The 'path' argument of ResourceProxy's methods getString(), getIStream(), // The 'path' argument of EmbeddedResourceProxy's methods getString(),
// getStringDecideOnPrefix() and getIStreamDecideOnPrefix() must: // getIStream(), getStringDecideOnPrefix() and getIStreamDecideOnPrefix()
// must:
// //
// - use UTF-8 encoding; // - use UTF-8 encoding;
// //
@@ -82,21 +85,21 @@
// //
// - if the path starts with a slash ('/'), a real file access is done; // - if the path starts with a slash ('/'), a real file access is done;
// //
// - if, on the other hand, it starts with ':/', ResourceProxy uses the // - if, on the other hand, it starts with ':/', EmbeddedResourceProxy uses
// embedded resource whose virtual path is the specified path without its // the embedded resource whose virtual path is the specified path without
// leading ':' (more precisely: the default-locale version of this // its leading ':' (more precisely: the default-locale version of this
// resource). // resource).
namespace simgear namespace simgear
{ {
class ResourceProxy class EmbeddedResourceProxy
{ {
public: public:
// 'virtualRoot' must start with a '/', e.g: '/FGData'. Whether it ends // 'virtualRoot' must start with a '/', e.g: '/FGData'. Whether it ends
// with a '/' doesn't make a difference. // with a '/' doesn't make a difference.
explicit ResourceProxy(const SGPath& realRoot, explicit EmbeddedResourceProxy(const SGPath& realRoot,
const std::string& virtualRoot, const std::string& virtualRoot,
bool useEmbeddedResourcesByDefault = true); bool useEmbeddedResourcesByDefault = true);
// Getters and setters for the corresponding data members // Getters and setters for the corresponding data members
SGPath getRealRoot() const; SGPath getRealRoot() const;
@@ -149,4 +152,4 @@ private:
} // of namespace simgear } // of namespace simgear
#endif // of FG_RESOURCEPROXY_HXX #endif // of FG_EMBEDDEDRESOURCEPROXY_HXX
@@ -40,7 +40,7 @@
#include <simgear/io/iostreams/zlibstream.hxx> #include <simgear/io/iostreams/zlibstream.hxx>
#include "EmbeddedResource.hxx" #include "EmbeddedResource.hxx"
#include "EmbeddedResourceManager.hxx" #include "EmbeddedResourceManager.hxx"
#include "ResourceProxy.hxx" #include "EmbeddedResourceProxy.hxx"
using std::cout; using std::cout;
using std::cerr; using std::cerr;
@@ -398,11 +398,11 @@ void test_getLocaleAndSelectLocale()
} }
} }
// Auxiliary function for test_ResourceProxy() // Auxiliary function for test_EmbeddedResourceProxy()
void auxTest_ResourceProxy_getIStream(unique_ptr<std::istream> iStream, void auxTest_EmbeddedResourceProxy_getIStream(unique_ptr<std::istream> iStream,
const string& contents) const string& contents)
{ {
cout << "Testing ResourceProxy::getIStream()" << endl; cout << "Testing EmbeddedResourceProxy::getIStream()" << endl;
iStream->exceptions(std::ios_base::badbit); iStream->exceptions(std::ios_base::badbit);
static constexpr std::size_t bufSize = 65536; static constexpr std::size_t bufSize = 65536;
@@ -421,9 +421,9 @@ void auxTest_ResourceProxy_getIStream(unique_ptr<std::istream> iStream,
SG_CHECK_EQUAL(result, contents); SG_CHECK_EQUAL(result, contents);
} }
void test_ResourceProxy() void test_EmbeddedResourceProxy()
{ {
cout << "Testing the ResourceProxy class" << endl; cout << "Testing the EmbeddedResourceProxy class" << endl;
// Initialize stuff we need and create two files containing the contents of // Initialize stuff we need and create two files containing the contents of
// the default-locale version of two embedded resources: those with virtual // the default-locale version of two embedded resources: those with virtual
@@ -456,14 +456,14 @@ void test_ResourceProxy()
} }
// 'proxy' defaults to using embedded resources // 'proxy' defaults to using embedded resources
const simgear::ResourceProxy proxy(tmpDir.path(), const simgear::EmbeddedResourceProxy proxy(tmpDir.path(), "/path/to",
"/path/to", /* useEmbeddedResourcesByDefault */
true /* useEmbeddedResourcesByDefault */); true);
simgear::ResourceProxy rproxy(tmpDir.path(), "/path/to"); simgear::EmbeddedResourceProxy rproxy(tmpDir.path(), "/path/to");
// 'rproxy' defaults to using real files // 'rproxy' defaults to using real files
rproxy.setUseEmbeddedResources(false); // could be done from the ctor too rproxy.setUseEmbeddedResources(false); // could be done from the ctor too
// Test ResourceProxy::getString() // Test EmbeddedResourceProxy::getString()
SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix("/resource1"), rs1); SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix("/resource1"), rs1);
SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix(":/resource1"), s1); SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix(":/resource1"), s1);
SG_CHECK_EQUAL(proxy.getString("/resource1", false), rs1); SG_CHECK_EQUAL(proxy.getString("/resource1", false), rs1);
@@ -478,20 +478,24 @@ void test_ResourceProxy()
SG_CHECK_EQUAL(proxy.getString("/resource2"), lipsum); SG_CHECK_EQUAL(proxy.getString("/resource2"), lipsum);
SG_CHECK_EQUAL(rproxy.getString("/resource2"), rlipsum); SG_CHECK_EQUAL(rproxy.getString("/resource2"), rlipsum);
// Test ResourceProxy::getIStream() // Test EmbeddedResourceProxy::getIStream()
auxTest_ResourceProxy_getIStream(proxy.getIStreamDecideOnPrefix("/resource1"), auxTest_EmbeddedResourceProxy_getIStream(
rs1); proxy.getIStreamDecideOnPrefix("/resource1"),
auxTest_ResourceProxy_getIStream(proxy.getIStreamDecideOnPrefix(":/resource1"), rs1);
s1); auxTest_EmbeddedResourceProxy_getIStream(
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource1"), s1); proxy.getIStreamDecideOnPrefix(":/resource1"),
auxTest_ResourceProxy_getIStream(rproxy.getIStream("/resource1"), rs1); s1);
auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource1"), s1);
auxTest_EmbeddedResourceProxy_getIStream(rproxy.getIStream("/resource1"), rs1);
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource2", false), auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource2", false),
rlipsum); rlipsum);
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource2", true), auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource2", true),
lipsum); lipsum);
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource2"), lipsum); auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource2"),
auxTest_ResourceProxy_getIStream(rproxy.getIStream("/resource2"), rlipsum); lipsum);
auxTest_EmbeddedResourceProxy_getIStream(rproxy.getIStream("/resource2"),
rlipsum);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
@@ -506,7 +510,7 @@ int main(int argc, char **argv)
test_addAlreadyExistingResource(); test_addAlreadyExistingResource();
test_localeDependencyOfResourceFetching(); test_localeDependencyOfResourceFetching();
test_getLocaleAndSelectLocale(); test_getLocaleAndSelectLocale();
test_ResourceProxy(); test_EmbeddedResourceProxy();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }