Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS EmbeddedResource.hxx EmbeddedResourceManager.hxx ResourceProxy.hxx)
|
||||
set(SOURCES EmbeddedResource.cxx EmbeddedResourceManager.cxx ResourceProxy.cxx)
|
||||
set(HEADERS EmbeddedResource.hxx
|
||||
EmbeddedResourceManager.hxx
|
||||
EmbeddedResourceProxy.hxx)
|
||||
set(SOURCES EmbeddedResource.cxx
|
||||
EmbeddedResourceManager.cxx
|
||||
EmbeddedResourceProxy.cxx)
|
||||
|
||||
simgear_component(embedded_resources embedded_resources
|
||||
"${SOURCES}" "${HEADERS}")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// -*- 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
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@@ -35,7 +36,7 @@
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include "EmbeddedResourceManager.hxx"
|
||||
#include "ResourceProxy.hxx"
|
||||
#include "EmbeddedResourceProxy.hxx"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
@@ -46,35 +47,36 @@ using std::unique_ptr;
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
ResourceProxy::ResourceProxy(const SGPath& realRoot, const string& virtualRoot,
|
||||
bool useEmbeddedResourcesByDefault)
|
||||
EmbeddedResourceProxy::EmbeddedResourceProxy(const SGPath& realRoot,
|
||||
const string& virtualRoot,
|
||||
bool useEmbeddedResourcesByDefault)
|
||||
: _realRoot(realRoot),
|
||||
_virtualRoot(normalizeVirtualRoot(virtualRoot)),
|
||||
_useEmbeddedResourcesByDefault(useEmbeddedResourcesByDefault)
|
||||
{ }
|
||||
|
||||
SGPath
|
||||
ResourceProxy::getRealRoot() const
|
||||
EmbeddedResourceProxy::getRealRoot() const
|
||||
{ return _realRoot; }
|
||||
|
||||
void
|
||||
ResourceProxy::setRealRoot(const SGPath& realRoot)
|
||||
EmbeddedResourceProxy::setRealRoot(const SGPath& realRoot)
|
||||
{ _realRoot = realRoot; }
|
||||
|
||||
string
|
||||
ResourceProxy::getVirtualRoot() const
|
||||
EmbeddedResourceProxy::getVirtualRoot() const
|
||||
{ return _virtualRoot; }
|
||||
|
||||
void
|
||||
ResourceProxy::setVirtualRoot(const string& virtualRoot)
|
||||
EmbeddedResourceProxy::setVirtualRoot(const string& virtualRoot)
|
||||
{ _virtualRoot = normalizeVirtualRoot(virtualRoot); }
|
||||
|
||||
bool
|
||||
ResourceProxy::getUseEmbeddedResources() const
|
||||
EmbeddedResourceProxy::getUseEmbeddedResources() const
|
||||
{ return _useEmbeddedResourcesByDefault; }
|
||||
|
||||
void
|
||||
ResourceProxy::setUseEmbeddedResources(bool useEmbeddedResources)
|
||||
EmbeddedResourceProxy::setUseEmbeddedResources(bool useEmbeddedResources)
|
||||
{ _useEmbeddedResourcesByDefault = useEmbeddedResources; }
|
||||
|
||||
// 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 '..'
|
||||
// component. The return value never ends with a slash.
|
||||
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;
|
||||
|
||||
// Make sure 'res' doesn't end with a '/'.
|
||||
@@ -97,21 +100,22 @@ ResourceProxy::normalizeVirtualRoot(const string& path)
|
||||
|
||||
// Static method
|
||||
void
|
||||
ResourceProxy::checkPath(const string& callerMethod, const string& path,
|
||||
bool allowStartWithColon) {
|
||||
EmbeddedResourceProxy::checkPath(const string& callerMethod, const string& path,
|
||||
bool allowStartWithColon)
|
||||
{
|
||||
if (path.empty()) {
|
||||
throw sg_format_exception(
|
||||
"Invalid empty path for ResourceProxy::" + callerMethod + "(): '" +
|
||||
path + "'", path);
|
||||
"Invalid empty path for EmbeddedResourceProxy::" +
|
||||
callerMethod + "(): '" + path + "'", path);
|
||||
} else if (allowStartWithColon &&
|
||||
!simgear::strutils::starts_with(path, ":/") && path[0] != '/') {
|
||||
throw sg_format_exception(
|
||||
"Invalid path for ResourceProxy::" + callerMethod + "(): it should "
|
||||
"start with either ':/' or '/'", path);
|
||||
"Invalid path for EmbeddedResourceProxy::" + callerMethod + "(): "
|
||||
"it should start with either ':/' or '/'", path);
|
||||
} else if (!allowStartWithColon && path[0] != '/') {
|
||||
throw sg_format_exception(
|
||||
"Invalid path for ResourceProxy::" + callerMethod + "(): it should "
|
||||
"start with a slash ('/')", path);
|
||||
"Invalid path for EmbeddedResourceProxy::" + callerMethod + "(): "
|
||||
"it should start with a slash ('/')", path);
|
||||
} else {
|
||||
const vector<string> components = simgear::strutils::split(path, "/");
|
||||
auto find = [&components](const string& s) -> bool {
|
||||
@@ -121,16 +125,18 @@ ResourceProxy::checkPath(const string& callerMethod, const string& path,
|
||||
|
||||
if (find(".") || find("..")) {
|
||||
throw sg_format_exception(
|
||||
"Invalid path for ResourceProxy::" + callerMethod + "(): "
|
||||
"Invalid path for EmbeddedResourceProxy::" + callerMethod + "(): "
|
||||
"'.' and '..' components are not allowed", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() == '/');
|
||||
|
||||
if (fromEmbeddedResource) {
|
||||
@@ -145,15 +151,16 @@ ResourceProxy::getIStream(const string& path, bool fromEmbeddedResource) const
|
||||
}
|
||||
|
||||
unique_ptr<std::istream>
|
||||
ResourceProxy::getIStream(const string& path) const
|
||||
EmbeddedResourceProxy::getIStream(const string& path) const
|
||||
{
|
||||
return getIStream(path, _useEmbeddedResourcesByDefault);
|
||||
}
|
||||
|
||||
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
|
||||
if (path.front() == '/') {
|
||||
@@ -170,11 +177,13 @@ ResourceProxy::getIStreamDecideOnPrefix(const string& path) const
|
||||
}
|
||||
|
||||
string
|
||||
ResourceProxy::getString(const string& path, bool fromEmbeddedResource) const
|
||||
EmbeddedResourceProxy::getString(const string& path, bool fromEmbeddedResource)
|
||||
const
|
||||
{
|
||||
string result;
|
||||
|
||||
ResourceProxy::checkPath(__func__, path, false /* allowStartWithColon */);
|
||||
EmbeddedResourceProxy::checkPath(__func__, path,
|
||||
false /* allowStartWithColon */);
|
||||
assert(!path.empty() && path.front() == '/');
|
||||
|
||||
if (fromEmbeddedResource) {
|
||||
@@ -216,17 +225,18 @@ ResourceProxy::getString(const string& path, bool fromEmbeddedResource) const
|
||||
}
|
||||
|
||||
string
|
||||
ResourceProxy::getString(const string& path) const
|
||||
EmbeddedResourceProxy::getString(const string& path) const
|
||||
{
|
||||
return getString(path, _useEmbeddedResourcesByDefault);
|
||||
}
|
||||
|
||||
string
|
||||
ResourceProxy::getStringDecideOnPrefix(const string& path) const
|
||||
EmbeddedResourceProxy::getStringDecideOnPrefix(const string& path) const
|
||||
{
|
||||
string result;
|
||||
|
||||
ResourceProxy::checkPath(__func__, path, true /* allowStartWithColon */);
|
||||
EmbeddedResourceProxy::checkPath(__func__, path,
|
||||
true /* allowStartWithColon */);
|
||||
|
||||
// 'path' is non-empty
|
||||
if (path.front() == '/') {
|
||||
@@ -1,6 +1,7 @@
|
||||
// -*- 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
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@@ -18,8 +19,8 @@
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301 USA.
|
||||
|
||||
#ifndef FG_RESOURCEPROXY_HXX
|
||||
#define FG_RESOURCEPROXY_HXX
|
||||
#ifndef FG_EMBEDDEDRESOURCEPROXY_HXX
|
||||
#define FG_EMBEDDEDRESOURCEPROXY_HXX
|
||||
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
@@ -27,26 +28,27 @@
|
||||
|
||||
#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
|
||||
// source to the other with minimal code changes, possibly even at runtime (in
|
||||
// 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::unique_ptr<std::istream> streamp = proxy.getIStream("/some/path");
|
||||
//
|
||||
// The methods ResourceProxy::getString(const std::string& path) and
|
||||
// ResourceProxy::getIStream(const std::string& path) decide whether to use
|
||||
// embedded resources or real files depending on the boolean value passed to
|
||||
// ResourceProxy::setUseEmbeddedResources() (also available as an optional
|
||||
// parameter to the ResourceProxy constructor, defaulting to true). It is
|
||||
// often most convenient to set this boolean once and then don't worry about
|
||||
// it anymore (it is stored inside ResourceProxy). Otherwise, if you want to
|
||||
// fetch resources some times from real files, other times from embedded
|
||||
// resources, you may use the following methods:
|
||||
// The methods getString(const std::string& path) and
|
||||
// getIStream(const std::string& path) of EmbeddedResourceProxy decide whether
|
||||
// to use embedded resources or real files depending on the boolean value
|
||||
// passed to EmbeddedResourceProxy::setUseEmbeddedResources() (also available
|
||||
// as an optional parameter to the EmbeddedResourceProxy constructor,
|
||||
// defaulting to true). It is often most convenient to set this boolean once
|
||||
// and then don't worry about it anymore (it is stored as a data member of
|
||||
// EmbeddedResourceProxy). Otherwise, if you want to fetch resources some
|
||||
// times from real files, other times from embedded resources, you may use the
|
||||
// following methods:
|
||||
//
|
||||
// // Retrieve contents using embedded resources
|
||||
// std:string s = proxy.getString("/some/path", true);
|
||||
@@ -56,8 +58,8 @@
|
||||
// std:string s = proxy.getString("/some/path", false);
|
||||
// std:string s = proxy.getStringDecideOnPrefix("/some/path");
|
||||
//
|
||||
// You can do exactly the same with ResourceProxy::getIStream() and
|
||||
// ResourceProxy::getIStreamDecideOnPrefix(), except they return an
|
||||
// You can do exactly the same with EmbeddedResourceProxy::getIStream() and
|
||||
// EmbeddedResourceProxy::getIStreamDecideOnPrefix(), except they return an
|
||||
// std::unique_ptr<std::istream> instead of an std::string.
|
||||
//
|
||||
// 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
|
||||
// precisely: the default-locale version of this resource).
|
||||
//
|
||||
// The 'path' argument of ResourceProxy's methods getString(), getIStream(),
|
||||
// getStringDecideOnPrefix() and getIStreamDecideOnPrefix() must:
|
||||
// The 'path' argument of EmbeddedResourceProxy's methods getString(),
|
||||
// getIStream(), getStringDecideOnPrefix() and getIStreamDecideOnPrefix()
|
||||
// must:
|
||||
//
|
||||
// - use UTF-8 encoding;
|
||||
//
|
||||
@@ -82,21 +85,21 @@
|
||||
//
|
||||
// - if the path starts with a slash ('/'), a real file access is done;
|
||||
//
|
||||
// - if, on the other hand, it starts with ':/', ResourceProxy uses the
|
||||
// embedded resource whose virtual path is the specified path without its
|
||||
// leading ':' (more precisely: the default-locale version of this
|
||||
// - if, on the other hand, it starts with ':/', EmbeddedResourceProxy uses
|
||||
// the embedded resource whose virtual path is the specified path without
|
||||
// its leading ':' (more precisely: the default-locale version of this
|
||||
// resource).
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
class ResourceProxy
|
||||
class EmbeddedResourceProxy
|
||||
{
|
||||
public:
|
||||
// 'virtualRoot' must start with a '/', e.g: '/FGData'. Whether it ends
|
||||
// with a '/' doesn't make a difference.
|
||||
explicit ResourceProxy(const SGPath& realRoot,
|
||||
const std::string& virtualRoot,
|
||||
bool useEmbeddedResourcesByDefault = true);
|
||||
explicit EmbeddedResourceProxy(const SGPath& realRoot,
|
||||
const std::string& virtualRoot,
|
||||
bool useEmbeddedResourcesByDefault = true);
|
||||
|
||||
// Getters and setters for the corresponding data members
|
||||
SGPath getRealRoot() const;
|
||||
@@ -149,4 +152,4 @@ private:
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
#endif // of FG_RESOURCEPROXY_HXX
|
||||
#endif // of FG_EMBEDDEDRESOURCEPROXY_HXX
|
||||
@@ -40,7 +40,7 @@
|
||||
#include <simgear/io/iostreams/zlibstream.hxx>
|
||||
#include "EmbeddedResource.hxx"
|
||||
#include "EmbeddedResourceManager.hxx"
|
||||
#include "ResourceProxy.hxx"
|
||||
#include "EmbeddedResourceProxy.hxx"
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
@@ -398,11 +398,11 @@ void test_getLocaleAndSelectLocale()
|
||||
}
|
||||
}
|
||||
|
||||
// Auxiliary function for test_ResourceProxy()
|
||||
void auxTest_ResourceProxy_getIStream(unique_ptr<std::istream> iStream,
|
||||
const string& contents)
|
||||
// Auxiliary function for test_EmbeddedResourceProxy()
|
||||
void auxTest_EmbeddedResourceProxy_getIStream(unique_ptr<std::istream> iStream,
|
||||
const string& contents)
|
||||
{
|
||||
cout << "Testing ResourceProxy::getIStream()" << endl;
|
||||
cout << "Testing EmbeddedResourceProxy::getIStream()" << endl;
|
||||
|
||||
iStream->exceptions(std::ios_base::badbit);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
// the default-locale version of two embedded resources: those with virtual
|
||||
@@ -456,14 +456,14 @@ void test_ResourceProxy()
|
||||
}
|
||||
|
||||
// 'proxy' defaults to using embedded resources
|
||||
const simgear::ResourceProxy proxy(tmpDir.path(),
|
||||
"/path/to",
|
||||
true /* useEmbeddedResourcesByDefault */);
|
||||
simgear::ResourceProxy rproxy(tmpDir.path(), "/path/to");
|
||||
const simgear::EmbeddedResourceProxy proxy(tmpDir.path(), "/path/to",
|
||||
/* useEmbeddedResourcesByDefault */
|
||||
true);
|
||||
simgear::EmbeddedResourceProxy rproxy(tmpDir.path(), "/path/to");
|
||||
// 'rproxy' defaults to using real files
|
||||
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"), s1);
|
||||
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(rproxy.getString("/resource2"), rlipsum);
|
||||
|
||||
// Test ResourceProxy::getIStream()
|
||||
auxTest_ResourceProxy_getIStream(proxy.getIStreamDecideOnPrefix("/resource1"),
|
||||
rs1);
|
||||
auxTest_ResourceProxy_getIStream(proxy.getIStreamDecideOnPrefix(":/resource1"),
|
||||
s1);
|
||||
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource1"), s1);
|
||||
auxTest_ResourceProxy_getIStream(rproxy.getIStream("/resource1"), rs1);
|
||||
// Test EmbeddedResourceProxy::getIStream()
|
||||
auxTest_EmbeddedResourceProxy_getIStream(
|
||||
proxy.getIStreamDecideOnPrefix("/resource1"),
|
||||
rs1);
|
||||
auxTest_EmbeddedResourceProxy_getIStream(
|
||||
proxy.getIStreamDecideOnPrefix(":/resource1"),
|
||||
s1);
|
||||
auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource1"), s1);
|
||||
auxTest_EmbeddedResourceProxy_getIStream(rproxy.getIStream("/resource1"), rs1);
|
||||
|
||||
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource2", false),
|
||||
rlipsum);
|
||||
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource2", true),
|
||||
lipsum);
|
||||
auxTest_ResourceProxy_getIStream(proxy.getIStream("/resource2"), lipsum);
|
||||
auxTest_ResourceProxy_getIStream(rproxy.getIStream("/resource2"), rlipsum);
|
||||
auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource2", false),
|
||||
rlipsum);
|
||||
auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource2", true),
|
||||
lipsum);
|
||||
auxTest_EmbeddedResourceProxy_getIStream(proxy.getIStream("/resource2"),
|
||||
lipsum);
|
||||
auxTest_EmbeddedResourceProxy_getIStream(rproxy.getIStream("/resource2"),
|
||||
rlipsum);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -506,7 +510,7 @@ int main(int argc, char **argv)
|
||||
test_addAlreadyExistingResource();
|
||||
test_localeDependencyOfResourceFetching();
|
||||
test_getLocaleAndSelectLocale();
|
||||
test_ResourceProxy();
|
||||
test_EmbeddedResourceProxy();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user