Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next

This commit is contained in:
gallaert
2017-10-09 22:04:36 +01:00
4 changed files with 107 additions and 86 deletions

View File

@@ -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}")

View File

@@ -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() == '/') {

View File

@@ -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

View File

@@ -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;
}