Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
@@ -49,7 +49,7 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7")
|
||||
# add a dependency on the versino file
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS version)
|
||||
|
||||
set(FIND_LIBRARY_USE_LIB64_PATHS ON)
|
||||
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
|
||||
|
||||
# use simgear version also as the SO version (if building SOs)
|
||||
SET(SIMGEAR_SOVERSION ${SIMGEAR_VERSION})
|
||||
|
||||
@@ -47,6 +47,12 @@ namespace canvas
|
||||
const std::string GEO = "-geo";
|
||||
const std::string HDG = "hdg";
|
||||
const std::string Map::TYPE_NAME = "map";
|
||||
const std::string WEB_MERCATOR = "webmercator";
|
||||
const std::string REF_LAT = "ref-lat";
|
||||
const std::string REF_LON = "ref-lon";
|
||||
const std::string SCREEN_RANGE = "screen-range";
|
||||
const std::string RANGE = "range";
|
||||
const std::string PROJECTION = "projection";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::staticInit()
|
||||
@@ -64,12 +70,16 @@ namespace canvas
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
ElementWeakPtr parent ):
|
||||
Group(canvas, node, parent_style, parent),
|
||||
// TODO make projection configurable
|
||||
_projection(new SansonFlamsteedProjection),
|
||||
_projection_dirty(true)
|
||||
Group(canvas, node, parent_style, parent)
|
||||
{
|
||||
staticInit();
|
||||
if (node->getChild(PROJECTION) &&
|
||||
(node->getChild(PROJECTION)->getStringValue() == WEB_MERCATOR)) {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new WebMercatorProjection();
|
||||
} else {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new SansonFlamsteedProjection();
|
||||
}
|
||||
_projection_dirty = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -162,10 +172,10 @@ namespace canvas
|
||||
if( child->getParent() != _node )
|
||||
return Group::childChanged(child);
|
||||
|
||||
if( child->getNameString() == "ref-lat"
|
||||
|| child->getNameString() == "ref-lon" )
|
||||
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
|
||||
_node->getDoubleValue("ref-lon") );
|
||||
if( child->getNameString() == REF_LAT
|
||||
|| child->getNameString() == REF_LON )
|
||||
_projection->setWorldPosition( _node->getDoubleValue(REF_LAT),
|
||||
_node->getDoubleValue(REF_LON) );
|
||||
else if( child->getNameString() == HDG )
|
||||
{
|
||||
_projection->setOrientation(child->getFloatValue());
|
||||
@@ -174,11 +184,23 @@ namespace canvas
|
||||
++it )
|
||||
hdgNodeChanged(*it);
|
||||
}
|
||||
else if( child->getNameString() == "range" )
|
||||
else if( child->getNameString() == RANGE )
|
||||
_projection->setRange(child->getDoubleValue());
|
||||
else if( child->getNameString() == "screen-range" )
|
||||
else if( child->getNameString() == SCREEN_RANGE )
|
||||
_projection->setScreenRange(child->getDoubleValue());
|
||||
else
|
||||
else if( child->getNameString() == PROJECTION ) {
|
||||
if (child->getStringValue() == WEB_MERCATOR) {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new WebMercatorProjection();
|
||||
} else {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new SansonFlamsteedProjection();
|
||||
}
|
||||
_projection->setWorldPosition(_node->getDoubleValue(REF_LAT),
|
||||
_node->getDoubleValue(REF_LON) );
|
||||
_projection->setOrientation(_node->getFloatValue(HDG));
|
||||
_projection->setScreenRange(_node->getDoubleValue(SCREEN_RANGE));
|
||||
_projection->setRange(_node->getDoubleValue(RANGE));
|
||||
_projection_dirty = true;
|
||||
} else
|
||||
return Group::childChanged(child);
|
||||
|
||||
_projection_dirty = true;
|
||||
|
||||
@@ -190,6 +190,32 @@ namespace canvas
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* WebMercator projection, relative to the projection center.
|
||||
* Required for Slippy Maps - i.e. openstreetmap
|
||||
*/
|
||||
class WebMercatorProjection:
|
||||
public HorizontalProjection
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual ScreenPosition project(double lat, double lon) const
|
||||
{
|
||||
double d_lat = lat - _ref_lat,
|
||||
d_lon = lon - _ref_lon;
|
||||
double r = 6378137.f / 1852; // Equatorial radius divided by ?
|
||||
|
||||
ScreenPosition pos;
|
||||
|
||||
pos.x = r * d_lon;
|
||||
pos.y = r * (log(tan(d_lat) + 1.0 / cos(d_lat)));
|
||||
//pos.x = lon;
|
||||
//pos.y = log(tan(lat) + 1.0 / cos(lat));
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS EmbeddedResource.hxx EmbeddedResourceManager.hxx)
|
||||
set(SOURCES EmbeddedResource.cxx EmbeddedResourceManager.cxx)
|
||||
set(HEADERS EmbeddedResource.hxx EmbeddedResourceManager.hxx ResourceProxy.hxx)
|
||||
set(SOURCES EmbeddedResource.cxx EmbeddedResourceManager.cxx ResourceProxy.cxx)
|
||||
|
||||
simgear_component(embedded_resources embedded_resources
|
||||
"${SOURCES}" "${HEADERS}")
|
||||
|
||||
247
simgear/embedded_resources/ResourceProxy.cxx
Normal file
247
simgear/embedded_resources/ResourceProxy.cxx
Normal file
@@ -0,0 +1,247 @@
|
||||
// -*- coding: utf-8 -*-
|
||||
//
|
||||
// ResourceProxy.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
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301 USA.
|
||||
|
||||
#include <simgear_config.h>
|
||||
|
||||
#include <algorithm> // std::find()
|
||||
#include <ios> // std::streamsize
|
||||
#include <istream>
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdlib> // std::size_t
|
||||
#include <cassert>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include "EmbeddedResourceManager.hxx"
|
||||
#include "ResourceProxy.hxx"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
ResourceProxy::ResourceProxy(const SGPath& realRoot, const string& virtualRoot,
|
||||
bool useEmbeddedResourcesByDefault)
|
||||
: _realRoot(realRoot),
|
||||
_virtualRoot(normalizeVirtualRoot(virtualRoot)),
|
||||
_useEmbeddedResourcesByDefault(useEmbeddedResourcesByDefault)
|
||||
{ }
|
||||
|
||||
SGPath
|
||||
ResourceProxy::getRealRoot() const
|
||||
{ return _realRoot; }
|
||||
|
||||
void
|
||||
ResourceProxy::setRealRoot(const SGPath& realRoot)
|
||||
{ _realRoot = realRoot; }
|
||||
|
||||
string
|
||||
ResourceProxy::getVirtualRoot() const
|
||||
{ return _virtualRoot; }
|
||||
|
||||
void
|
||||
ResourceProxy::setVirtualRoot(const string& virtualRoot)
|
||||
{ _virtualRoot = normalizeVirtualRoot(virtualRoot); }
|
||||
|
||||
bool
|
||||
ResourceProxy::getUseEmbeddedResources() const
|
||||
{ return _useEmbeddedResourcesByDefault; }
|
||||
|
||||
void
|
||||
ResourceProxy::setUseEmbeddedResources(bool useEmbeddedResources)
|
||||
{ _useEmbeddedResourcesByDefault = useEmbeddedResources; }
|
||||
|
||||
// Static method: normalize the 'virtualRoot' argument of the constructor
|
||||
//
|
||||
// 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)
|
||||
{
|
||||
ResourceProxy::checkPath(__func__, path, false /* allowStartWithColon */);
|
||||
string res = path;
|
||||
|
||||
// Make sure 'res' doesn't end with a '/'.
|
||||
while (!res.empty() && res.back() == '/') {
|
||||
res.pop_back(); // This will ease path concatenation
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Static method
|
||||
void
|
||||
ResourceProxy::checkPath(const string& callerMethod, const string& path,
|
||||
bool allowStartWithColon) {
|
||||
if (path.empty()) {
|
||||
throw sg_format_exception(
|
||||
"Invalid empty path for ResourceProxy::" + 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);
|
||||
} else if (!allowStartWithColon && path[0] != '/') {
|
||||
throw sg_format_exception(
|
||||
"Invalid path for ResourceProxy::" + callerMethod + "(): it should "
|
||||
"start with a slash ('/')", path);
|
||||
} else {
|
||||
const vector<string> components = simgear::strutils::split(path, "/");
|
||||
auto find = [&components](const string& s) -> bool {
|
||||
return (std::find(components.begin(), components.end(), s) !=
|
||||
components.end());
|
||||
};
|
||||
|
||||
if (find(".") || find("..")) {
|
||||
throw sg_format_exception(
|
||||
"Invalid path for ResourceProxy::" + callerMethod + "(): "
|
||||
"'.' and '..' components are not allowed", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<std::istream>
|
||||
ResourceProxy::getIStream(const string& path, bool fromEmbeddedResource) const
|
||||
{
|
||||
ResourceProxy::checkPath(__func__, path, false /* allowStartWithColon */);
|
||||
assert(!path.empty() && path.front() == '/');
|
||||
|
||||
if (fromEmbeddedResource) {
|
||||
const auto& embeddedResMgr = simgear::EmbeddedResourceManager::instance();
|
||||
return embeddedResMgr->getIStream(
|
||||
_virtualRoot + path,
|
||||
""); // fetch the default-locale version of the resource
|
||||
} else {
|
||||
const SGPath sgPath = _realRoot / path.substr(std::size_t(1));
|
||||
return unique_ptr<std::istream>(new sg_ifstream(sgPath));
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<std::istream>
|
||||
ResourceProxy::getIStream(const string& path) const
|
||||
{
|
||||
return getIStream(path, _useEmbeddedResourcesByDefault);
|
||||
}
|
||||
|
||||
unique_ptr<std::istream>
|
||||
ResourceProxy::getIStreamDecideOnPrefix(const string& path) const
|
||||
{
|
||||
ResourceProxy::checkPath(__func__, path, true /* allowStartWithColon */);
|
||||
|
||||
// 'path' is non-empty
|
||||
if (path.front() == '/') {
|
||||
return getIStream(path, false /* fromEmbeddedResource */);
|
||||
} else if (path.front() == ':') {
|
||||
assert(path.size() >= 2 && path[1] == '/');
|
||||
// Skip the leading ':'
|
||||
return getIStream(path.substr(std::size_t(1)),
|
||||
true /* fromEmbeddedResource */);
|
||||
} else {
|
||||
// The checkPath() call should make it impossible to reach this point.
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
ResourceProxy::getString(const string& path, bool fromEmbeddedResource) const
|
||||
{
|
||||
string result;
|
||||
|
||||
ResourceProxy::checkPath(__func__, path, false /* allowStartWithColon */);
|
||||
assert(!path.empty() && path.front() == '/');
|
||||
|
||||
if (fromEmbeddedResource) {
|
||||
const auto& embeddedResMgr = simgear::EmbeddedResourceManager::instance();
|
||||
// Fetch the default-locale version of the resource
|
||||
result = embeddedResMgr->getString(_virtualRoot + path, "");
|
||||
} else {
|
||||
const SGPath sgPath = _realRoot / path.substr(std::size_t(1));
|
||||
result.reserve(sgPath.sizeInBytes());
|
||||
const unique_ptr<std::istream> streamp = getIStream(path,
|
||||
fromEmbeddedResource);
|
||||
std::streamsize nbCharsRead;
|
||||
|
||||
// Allocate a buffer
|
||||
static constexpr std::size_t bufSize = 65536;
|
||||
static_assert(bufSize <= std::numeric_limits<std::streamsize>::max(),
|
||||
"Type std::streamsize is unexpectedly small");
|
||||
static_assert(bufSize <= std::numeric_limits<string::size_type>::max(),
|
||||
"Type std::string::size_type is unexpectedly small");
|
||||
unique_ptr<char[]> buf(new char[bufSize]);
|
||||
|
||||
do {
|
||||
streamp->read(buf.get(), bufSize);
|
||||
nbCharsRead = streamp->gcount();
|
||||
|
||||
if (nbCharsRead > 0) {
|
||||
result.append(buf.get(), nbCharsRead);
|
||||
}
|
||||
} while (*streamp);
|
||||
|
||||
// streamp->fail() would *not* indicate an error, due to the semantics
|
||||
// of std::istream::read().
|
||||
if (streamp->bad()) {
|
||||
throw sg_io_exception("Error reading from file", sg_location(path));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string
|
||||
ResourceProxy::getString(const string& path) const
|
||||
{
|
||||
return getString(path, _useEmbeddedResourcesByDefault);
|
||||
}
|
||||
|
||||
string
|
||||
ResourceProxy::getStringDecideOnPrefix(const string& path) const
|
||||
{
|
||||
string result;
|
||||
|
||||
ResourceProxy::checkPath(__func__, path, true /* allowStartWithColon */);
|
||||
|
||||
// 'path' is non-empty
|
||||
if (path.front() == '/') {
|
||||
result = getString(path, false /* fromEmbeddedResource */);
|
||||
} else if (path.front() == ':') {
|
||||
assert(path.size() >= 2 && path[1] == '/');
|
||||
// Skip the leading ':'
|
||||
result = getString(path.substr(std::size_t(1)),
|
||||
true /* fromEmbeddedResource */);
|
||||
} else {
|
||||
// The checkPath() call should make it impossible to reach this point.
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // of namespace simgear
|
||||
152
simgear/embedded_resources/ResourceProxy.hxx
Normal file
152
simgear/embedded_resources/ResourceProxy.hxx
Normal file
@@ -0,0 +1,152 @@
|
||||
// -*- coding: utf-8 -*-
|
||||
//
|
||||
// ResourceProxy.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
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301 USA.
|
||||
|
||||
#ifndef FG_RESOURCEPROXY_HXX
|
||||
#define FG_RESOURCEPROXY_HXX
|
||||
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
// The ResourceProxy 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):
|
||||
//
|
||||
// simgear::ResourceProxy 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:
|
||||
//
|
||||
// // Retrieve contents using embedded resources
|
||||
// std:string s = proxy.getString("/some/path", true);
|
||||
// std:string s = proxy.getStringDecideOnPrefix(":/some/path");
|
||||
//
|
||||
// // Retrieve contents using real files
|
||||
// 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
|
||||
// std::unique_ptr<std::istream> instead of an std::string.
|
||||
//
|
||||
// Given how the 'proxy' object was constructed above, each of these calls
|
||||
// will fetch data from either the real file $FG_ROOT/some/path or the
|
||||
// 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:
|
||||
//
|
||||
// - use UTF-8 encoding;
|
||||
//
|
||||
// - start with:
|
||||
// * either '/' or ':/' for the 'DecideOnPrefix' variants;
|
||||
// * only '/' for the other methods.
|
||||
//
|
||||
// - have its components separated by slashes;
|
||||
//
|
||||
// - not contain any '.' or '..' component.
|
||||
//
|
||||
// For the 'DecideOnPrefix' variants:
|
||||
//
|
||||
// - 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
|
||||
// resource).
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
class ResourceProxy
|
||||
{
|
||||
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);
|
||||
|
||||
// Getters and setters for the corresponding data members
|
||||
SGPath getRealRoot() const;
|
||||
void setRealRoot(const SGPath& realRoot);
|
||||
|
||||
std::string getVirtualRoot() const;
|
||||
void setVirtualRoot(const std::string& virtualRoot);
|
||||
|
||||
bool getUseEmbeddedResources() const;
|
||||
void setUseEmbeddedResources(bool useEmbeddedResources);
|
||||
|
||||
// Get an std::istream to read from a file or from an embedded resource.
|
||||
std::unique_ptr<std::istream>
|
||||
getIStream(const std::string& path, bool fromEmbeddedResource) const;
|
||||
|
||||
std::unique_ptr<std::istream>
|
||||
getIStream(const std::string& path) const;
|
||||
|
||||
std::unique_ptr<std::istream>
|
||||
getIStreamDecideOnPrefix(const std::string& path) const;
|
||||
|
||||
// Get a file or embedded resource contents as a string.
|
||||
std::string
|
||||
getString(const std::string& path, bool fromEmbeddedResource) const;
|
||||
|
||||
std::string
|
||||
getString(const std::string& path) const;
|
||||
|
||||
std::string
|
||||
getStringDecideOnPrefix(const std::string& path) const;
|
||||
|
||||
private:
|
||||
// Check that 'path' starts with either ':/' or '/', and doesn't contain any
|
||||
// '..' component ('path' may only start with ':/' if 'allowStartWithColon'
|
||||
// is true).
|
||||
static void
|
||||
checkPath(const std::string& callerMethod, const std::string& path,
|
||||
bool allowStartWithColon);
|
||||
|
||||
// Normalize the 'virtualRoot' argument of the constructor. The argument
|
||||
// must start with a '/' and mustn't contain any '.' or '..' component. The
|
||||
// return value never ends with a '/'.
|
||||
static std::string
|
||||
normalizeVirtualRoot(const std::string& path);
|
||||
|
||||
SGPath _realRoot;
|
||||
std::string _virtualRoot;
|
||||
bool _useEmbeddedResourcesByDefault;
|
||||
};
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
#endif // of FG_RESOURCEPROXY_HXX
|
||||
@@ -33,11 +33,14 @@
|
||||
#include <cstddef> // std::size_t
|
||||
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/io/iostreams/CharArrayStream.hxx>
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
#include <simgear/io/iostreams/zlibstream.hxx>
|
||||
#include "EmbeddedResource.hxx"
|
||||
#include "EmbeddedResourceManager.hxx"
|
||||
#include "ResourceProxy.hxx"
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
@@ -395,6 +398,102 @@ void test_getLocaleAndSelectLocale()
|
||||
}
|
||||
}
|
||||
|
||||
// Auxiliary function for test_ResourceProxy()
|
||||
void auxTest_ResourceProxy_getIStream(unique_ptr<std::istream> iStream,
|
||||
const string& contents)
|
||||
{
|
||||
cout << "Testing ResourceProxy::getIStream()" << endl;
|
||||
|
||||
iStream->exceptions(std::ios_base::badbit);
|
||||
static constexpr std::size_t bufSize = 65536;
|
||||
unique_ptr<char[]> buf(new char[bufSize]); // intermediate buffer
|
||||
string result;
|
||||
|
||||
do {
|
||||
iStream->read(buf.get(), bufSize);
|
||||
result.append(buf.get(), iStream->gcount());
|
||||
} while (*iStream); // iStream *points* to an std::istream
|
||||
|
||||
// 1) If set, badbit would have caused an exception to be raised (see above).
|
||||
// 2) failbit doesn't necessarily indicate an error here: it is set as soon
|
||||
// as the read() call can't provide the requested number of characters.
|
||||
SG_VERIFY(iStream->eof() && !iStream->bad());
|
||||
SG_CHECK_EQUAL(result, contents);
|
||||
}
|
||||
|
||||
void test_ResourceProxy()
|
||||
{
|
||||
cout << "Testing the ResourceProxy 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
|
||||
// paths '/path/to/resource1' and '/path/to/resource2'.
|
||||
const auto& resMgr = EmbeddedResourceManager::instance();
|
||||
simgear::Dir tmpDir = simgear::Dir::tempDir("FlightGear");
|
||||
tmpDir.setRemoveOnDestroy();
|
||||
|
||||
const SGPath path1 = tmpDir.path() / "resource1";
|
||||
const SGPath path2 = tmpDir.path() / "resource2";
|
||||
|
||||
sg_ofstream out1(path1);
|
||||
sg_ofstream out2(path2);
|
||||
const string s1 = resMgr->getString("/path/to/resource1", "");
|
||||
// To make sure in these tests that we can tell whether something came from
|
||||
// a real file or from an embedded resource.
|
||||
const string rs1 = s1 + " from real file";
|
||||
const string rlipsum = lipsum + " from real file";
|
||||
|
||||
out1 << rs1;
|
||||
out1.close();
|
||||
if (!out1) {
|
||||
throw sg_io_exception("Error writing to file", sg_location(path1));
|
||||
}
|
||||
|
||||
out2 << rlipsum;
|
||||
out2.close();
|
||||
if (!out2) {
|
||||
throw sg_io_exception("Error writing to file", sg_location(path2));
|
||||
}
|
||||
|
||||
// 'proxy' defaults to using embedded resources
|
||||
const simgear::ResourceProxy proxy(tmpDir.path(),
|
||||
"/path/to",
|
||||
true /* useEmbeddedResourcesByDefault */);
|
||||
simgear::ResourceProxy rproxy(tmpDir.path(), "/path/to");
|
||||
// 'rproxy' defaults to using real files
|
||||
rproxy.setUseEmbeddedResources(false); // could be done from the ctor too
|
||||
|
||||
// Test ResourceProxy::getString()
|
||||
SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix("/resource1"), rs1);
|
||||
SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix(":/resource1"), s1);
|
||||
SG_CHECK_EQUAL(proxy.getString("/resource1", false), rs1);
|
||||
SG_CHECK_EQUAL(proxy.getString("/resource1", true), s1);
|
||||
SG_CHECK_EQUAL(proxy.getString("/resource1"), s1);
|
||||
SG_CHECK_EQUAL(rproxy.getString("/resource1"), rs1);
|
||||
|
||||
SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix("/resource2"), rlipsum);
|
||||
SG_CHECK_EQUAL(proxy.getStringDecideOnPrefix(":/resource2"), lipsum);
|
||||
SG_CHECK_EQUAL(proxy.getString("/resource2", false), rlipsum);
|
||||
SG_CHECK_EQUAL(proxy.getString("/resource2", true), lipsum);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Initialize the EmbeddedResourceManager instance, add a few resources
|
||||
@@ -407,6 +506,7 @@ int main(int argc, char **argv)
|
||||
test_addAlreadyExistingResource();
|
||||
test_localeDependencyOfResourceFetching();
|
||||
test_getLocaleAndSelectLocale();
|
||||
test_ResourceProxy();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
void finishedRequest(const RepoRequestPtr& req);
|
||||
|
||||
HTTPDirectory* getOrCreateDirectory(const std::string& path);
|
||||
bool deleteDirectory(const std::string& path);
|
||||
bool deleteDirectory(const std::string& relPath, const SGPath& absPath);
|
||||
|
||||
typedef std::vector<HTTPDirectory*> DirectoryVector;
|
||||
DirectoryVector directories;
|
||||
@@ -317,7 +317,8 @@ public:
|
||||
ChildInfoList::iterator c = findIndexChild(it->file());
|
||||
if (c == children.end()) {
|
||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "is orphan '" << it->file() << "'" );
|
||||
orphans.push_back(it->file());
|
||||
|
||||
orphans.push_back(it->file());
|
||||
} else if (c->hash != hash) {
|
||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "hash mismatch'" << it->file() );
|
||||
// file exists, but hash mismatch, schedule update
|
||||
@@ -534,7 +535,7 @@ private:
|
||||
|
||||
std::string fpath = _relativePath + "/" + name;
|
||||
if (p.isDir()) {
|
||||
ok = _repository->deleteDirectory(fpath);
|
||||
ok = _repository->deleteDirectory(fpath, p);
|
||||
} else {
|
||||
// remove the hash cache entry
|
||||
_repository->updatedFileContents(p, std::string());
|
||||
@@ -1044,25 +1045,26 @@ HTTPRepository::failure() const
|
||||
return d;
|
||||
}
|
||||
|
||||
bool HTTPRepoPrivate::deleteDirectory(const std::string& path)
|
||||
bool HTTPRepoPrivate::deleteDirectory(const std::string& relPath, const SGPath& absPath)
|
||||
{
|
||||
DirectoryWithPath p(path);
|
||||
DirectoryVector::iterator it = std::find_if(directories.begin(), directories.end(), p);
|
||||
DirectoryWithPath p(relPath);
|
||||
auto it = std::find_if(directories.begin(), directories.end(), p);
|
||||
if (it != directories.end()) {
|
||||
HTTPDirectory* d = *it;
|
||||
assert(d->absolutePath() == absPath);
|
||||
directories.erase(it);
|
||||
Dir dir(d->absolutePath());
|
||||
bool result = dir.remove(true);
|
||||
|
||||
// update the hash cache too
|
||||
updatedFileContents(d->absolutePath(), std::string());
|
||||
|
||||
delete d;
|
||||
} else {
|
||||
// we encounter this code path when deleting an orphaned directory
|
||||
}
|
||||
|
||||
Dir dir(absPath);
|
||||
bool result = dir.remove(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
// update the hash cache too
|
||||
updatedFileContents(absPath, std::string());
|
||||
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
void HTTPRepoPrivate::makeRequest(RepoRequestPtr req)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <simgear/sg_inlines.h>
|
||||
#include <simgear/io/sg_file.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
|
||||
@@ -92,7 +93,8 @@ public:
|
||||
END_OF_ARCHIVE,
|
||||
ERROR_STATE, ///< states above this are error conditions
|
||||
BAD_ARCHIVE,
|
||||
BAD_DATA
|
||||
BAD_DATA,
|
||||
FILTER_STOPPED
|
||||
} State;
|
||||
|
||||
SGPath path;
|
||||
@@ -110,10 +112,13 @@ public:
|
||||
bool haveInitedZLib;
|
||||
bool uncompressedData; // set if reading a plain .tar (not tar.gz)
|
||||
uint8_t* headerPtr;
|
||||
|
||||
TarExtractorPrivate() :
|
||||
TarExtractor* outer;
|
||||
bool skipCurrentEntry = false;
|
||||
|
||||
TarExtractorPrivate(TarExtractor* o) :
|
||||
haveInitedZLib(false),
|
||||
uncompressedData(false)
|
||||
uncompressedData(false),
|
||||
outer(o)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -129,7 +134,10 @@ public:
|
||||
}
|
||||
|
||||
if (state == READING_FILE) {
|
||||
currentFile->close();
|
||||
if (currentFile) {
|
||||
currentFile->close();
|
||||
currentFile.reset();
|
||||
}
|
||||
size_t pad = currentFileSize % TAR_HEADER_BLOCK_SIZE;
|
||||
if (pad) {
|
||||
bytesRemaining = TAR_HEADER_BLOCK_SIZE - pad;
|
||||
@@ -177,26 +185,36 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
skipCurrentEntry = false;
|
||||
std::string tarPath = std::string(header.prefix) + std::string(header.fileName);
|
||||
|
||||
if (!isSafePath(tarPath)) {
|
||||
//state = BAD_ARCHIVE;
|
||||
SG_LOG(SG_IO, SG_WARN, "bad tar path:" << tarPath);
|
||||
//return;
|
||||
skipCurrentEntry = true;
|
||||
}
|
||||
|
||||
SGPath p = path;
|
||||
p.append(tarPath);
|
||||
|
||||
auto result = outer->filterPath(tarPath);
|
||||
if (result == TarExtractor::Stop) {
|
||||
setState(FILTER_STOPPED);
|
||||
return;
|
||||
} else if (result == TarExtractor::Skipped) {
|
||||
skipCurrentEntry = true;
|
||||
}
|
||||
|
||||
SGPath p = path / tarPath;
|
||||
if (header.typeflag == DIRTYPE) {
|
||||
Dir dir(p);
|
||||
dir.create(0755);
|
||||
if (!skipCurrentEntry) {
|
||||
Dir dir(p);
|
||||
dir.create(0755);
|
||||
}
|
||||
setState(READING_HEADER);
|
||||
} else if ((header.typeflag == REGTYPE) || (header.typeflag == AREGTYPE)) {
|
||||
currentFileSize = ::strtol(header.size, NULL, 8);
|
||||
bytesRemaining = currentFileSize;
|
||||
currentFile.reset(new SGBinaryFile(p));
|
||||
currentFile->open(SG_IO_OUT);
|
||||
if (!skipCurrentEntry) {
|
||||
currentFile.reset(new SGBinaryFile(p));
|
||||
currentFile->open(SG_IO_OUT);
|
||||
}
|
||||
setState(READING_FILE);
|
||||
} else {
|
||||
SG_LOG(SG_IO, SG_WARN, "Unsupported tar file type:" << header.typeflag);
|
||||
@@ -212,7 +230,9 @@ public:
|
||||
|
||||
size_t curBytes = std::min(bytesRemaining, count);
|
||||
if (state == READING_FILE) {
|
||||
currentFile->write(bytes, curBytes);
|
||||
if (currentFile) {
|
||||
currentFile->write(bytes, curBytes);
|
||||
}
|
||||
bytesRemaining -= curBytes;
|
||||
} else if ((state == READING_HEADER) || (state == PRE_END_OF_ARCHVE) || (state == END_OF_ARCHIVE)) {
|
||||
memcpy(headerPtr, bytes, curBytes);
|
||||
@@ -264,7 +284,7 @@ public:
|
||||
};
|
||||
|
||||
TarExtractor::TarExtractor(const SGPath& rootPath) :
|
||||
d(new TarExtractorPrivate)
|
||||
d(new TarExtractorPrivate(this))
|
||||
{
|
||||
|
||||
d->path = rootPath;
|
||||
@@ -397,7 +417,7 @@ bool TarExtractor::isTarData(const uint8_t* bytes, size_t count)
|
||||
SG_LOG(SG_IO, SG_WARN, "insufficient data for header");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
header = reinterpret_cast<UstarHeaderBlock*>(zlibOutput);
|
||||
} else {
|
||||
// uncompressed tar
|
||||
@@ -417,4 +437,11 @@ bool TarExtractor::isTarData(const uint8_t* bytes, size_t count)
|
||||
return true;
|
||||
}
|
||||
|
||||
auto TarExtractor::filterPath(std::string& pathToExtract)
|
||||
-> PathResult
|
||||
{
|
||||
SG_UNUSED(pathToExtract);
|
||||
return Accepted;
|
||||
}
|
||||
|
||||
} // of simgear
|
||||
|
||||
@@ -43,7 +43,17 @@ public:
|
||||
|
||||
bool hasError() const;
|
||||
|
||||
protected:
|
||||
enum PathResult {
|
||||
Accepted,
|
||||
Skipped,
|
||||
Modified,
|
||||
Stop
|
||||
};
|
||||
|
||||
virtual PathResult filterPath(std::string& pathToExtract);
|
||||
private:
|
||||
friend class TarExtractorPrivate;
|
||||
std::unique_ptr<TarExtractorPrivate> d;
|
||||
};
|
||||
|
||||
|
||||
@@ -538,6 +538,33 @@ namespace simgear {
|
||||
unsigned long long readNonNegativeInt<unsigned long long, 16>(
|
||||
const std::string& s);
|
||||
#endif
|
||||
|
||||
// parse a time string ([+/-]%f[:%f[:%f]]) into hours
|
||||
double readTime(const string& time_in)
|
||||
{
|
||||
if (time_in.empty()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const bool negativeSign = time_in.front() == '-';
|
||||
const string_list pieces = split(time_in, ":");
|
||||
if (pieces.size() > 3) {
|
||||
throw sg_format_exception("Unable to parse time string, too many pieces", time_in);
|
||||
}
|
||||
|
||||
const int hours = std::abs(to_int(pieces.front()));
|
||||
int minutes = 0, seconds = 0;
|
||||
if (pieces.size() > 1) {
|
||||
minutes = to_int(pieces.at(1));
|
||||
if (pieces.size() > 2) {
|
||||
seconds = to_int(pieces.at(2));
|
||||
}
|
||||
}
|
||||
|
||||
double result = hours + (minutes / 60.0) + (seconds / 3600.0);
|
||||
return negativeSign ? -result : result;
|
||||
}
|
||||
|
||||
|
||||
int compare_versions(const string& v1, const string& v2, int maxComponents)
|
||||
{
|
||||
|
||||
@@ -209,6 +209,16 @@ namespace simgear {
|
||||
typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||||
T readNonNegativeInt(const std::string& s);
|
||||
|
||||
|
||||
/**
|
||||
* Read a time value, seperated by colons, as a value in hours.
|
||||
* Allowable input is ([+/-]%f[:%f[:%f]])
|
||||
* i.e 15:04:35 is parsed as 15 + (04 / 60) + (35 / 2600)
|
||||
* This code is moved from flightgear's options.cxx where it was called
|
||||
* parse_time(),
|
||||
*/
|
||||
double readTime(const std::string& s);
|
||||
|
||||
/**
|
||||
* Convert a string representing a boolean, to a bool.
|
||||
* Accepted values include YES, true, 0, 1, false, no, True,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/constants.h>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
@@ -581,6 +582,29 @@ void test_error_string()
|
||||
SG_CHECK_GT(strutils::error_string(saved_errno).size(), 0);
|
||||
}
|
||||
|
||||
void test_readTime()
|
||||
{
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime(""), 0.0);
|
||||
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("11"), 11.0);
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("+11"), 11.0);
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("-11"), -11.0);
|
||||
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("11:30"), 11.5);
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("+11:15"), 11.25);
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("-11:45"), -11.75);
|
||||
|
||||
const double seconds = 1 / 3600.0;
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("11:30:00"), 11.5);
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("+11:15:05"), 11.25 + 5 * seconds);
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("-11:45:15"), -(11.75 + 15 * seconds));
|
||||
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("0:0:0"), 0);
|
||||
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("0:0:28"), 28 * seconds);
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("-0:0:28"), -28 * seconds);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
test_strip();
|
||||
@@ -599,6 +623,7 @@ int main(int argc, char* argv[])
|
||||
test_md5_hex();
|
||||
test_error_string();
|
||||
test_propPathMatch();
|
||||
|
||||
test_readTime();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ static naRef f_fmod(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
if(naIsNil(a) || naIsNil(b))
|
||||
naRuntimeError(c, "non numeric arguments to fmod()");
|
||||
|
||||
|
||||
a.num = fmod(a.num, b.num);
|
||||
return VALIDATE(a);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ static naRef f_clamp(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
naRef min = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
naRef max = naNumValue(argc > 2 ? args[2] : naNil());
|
||||
|
||||
|
||||
if(naIsNil(a) || naIsNil(min) || naIsNil(max))
|
||||
naRuntimeError(c, "non numeric arguments to clamp()");
|
||||
|
||||
@@ -133,10 +133,10 @@ static naRef f_periodic(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
naRef x = naNumValue(argc > 2 ? args[2] : naNil());
|
||||
|
||||
|
||||
if(naIsNil(a) || naIsNil(b) || naIsNil(x))
|
||||
naRuntimeError(c, "non numeric arguments to periodic()");
|
||||
|
||||
|
||||
range = b.num - a.num;
|
||||
x.num = x.num - range*floor((x.num - a.num)/range);
|
||||
// two security checks that can only happen due to roundoff
|
||||
@@ -145,7 +145,7 @@ static naRef f_periodic(naContext c, naRef me, int argc, naRef* args)
|
||||
if (b.num <= x.num)
|
||||
x.num = b.num;
|
||||
return VALIDATE(x);
|
||||
|
||||
|
||||
// x.num = SGMiscd::normalizePeriodic(a, b, x);
|
||||
return VALIDATE(x);
|
||||
}
|
||||
@@ -156,7 +156,7 @@ static naRef f_round(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
#ifdef _MSC_VER
|
||||
double x,y;
|
||||
#endif
|
||||
#endif
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric arguments to round()");
|
||||
if (naIsNil(b))
|
||||
@@ -169,21 +169,31 @@ static naRef f_round(naContext c, naRef me, int argc, naRef* args)
|
||||
double x = round(a.num / b.num);
|
||||
#endif
|
||||
a.num = x * b.num;
|
||||
|
||||
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
|
||||
static naRef f_tan(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric arguments to tan()");
|
||||
|
||||
|
||||
a.num = tan(a.num);
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_atan(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric arguments to tan()");
|
||||
|
||||
a.num = atan(a.num);
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_asin(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
@@ -210,15 +220,16 @@ static naCFuncItem funcs[] = {
|
||||
{ "pow", f_pow },
|
||||
{ "sqrt", f_sqrt },
|
||||
{ "atan2", f_atan2 },
|
||||
{ "atan", f_atan },
|
||||
{ "floor", f_floor },
|
||||
{ "ceil", f_ceil },
|
||||
{ "fmod", f_fmod },
|
||||
{ "clamp", f_clamp },
|
||||
{ "periodic", f_periodic },
|
||||
{ "round", f_round },
|
||||
{ "tan", f_tan },
|
||||
{ "periodic", f_periodic },
|
||||
{ "round", f_round },
|
||||
{ "tan", f_tan },
|
||||
{ "acos", f_acos },
|
||||
{ "asin", f_asin },
|
||||
{ "asin", f_asin },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ SGLightFactory::getLights(const SGDirectionalLightBin& lights)
|
||||
//stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
|
||||
osg::DrawArrays* drawArrays;
|
||||
drawArrays = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,
|
||||
drawArrays = new osg::DrawArrays(osg::PrimitiveSet::POINTS,
|
||||
0, vertices->size());
|
||||
geometry->addPrimitiveSet(drawArrays);
|
||||
return geometry;
|
||||
|
||||
@@ -19,16 +19,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
#include <simgear_config.h>
|
||||
|
||||
#include "StateMachine.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <set>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/SGBinding.hxx>
|
||||
@@ -44,7 +41,7 @@ typedef std::vector<StateMachine::State_ptr> StatePtrVec;
|
||||
static void readBindingList(SGPropertyNode* desc, const std::string& name,
|
||||
SGPropertyNode* root, SGBindingList& result)
|
||||
{
|
||||
BOOST_FOREACH(SGPropertyNode* b, desc->getChildren(name)) {
|
||||
for (auto b : desc->getChildren(name)) {
|
||||
SGBinding* bind = new SGBinding;
|
||||
bind->read(b, root);
|
||||
result.push_back(bind);
|
||||
@@ -85,7 +82,7 @@ public:
|
||||
void computeEligibleTransitions()
|
||||
{
|
||||
_eligible.clear();
|
||||
BOOST_FOREACH(Transition_ptr t, _transitions) {
|
||||
for (Transition_ptr t : _transitions) {
|
||||
if (t->applicableForState(_currentState)) {
|
||||
_eligible.push_back(t.ptr());
|
||||
}
|
||||
@@ -358,7 +355,7 @@ void StateMachine::update(double aDt)
|
||||
|
||||
Transition_ptr trigger;
|
||||
|
||||
BOOST_FOREACH(Transition* trans, d->_eligible) {
|
||||
for (auto trans : d->_eligible) {
|
||||
if (trans->evaluate()) {
|
||||
if (trigger != Transition_ptr()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "ambiguous transitions! "
|
||||
@@ -379,7 +376,7 @@ void StateMachine::update(double aDt)
|
||||
|
||||
StateMachine::State_ptr StateMachine::findStateByName(const std::string& aName) const
|
||||
{
|
||||
BOOST_FOREACH(State_ptr sp, d->_states) {
|
||||
for (auto sp : d->_states) {
|
||||
if (sp->name() == aName) {
|
||||
return sp;
|
||||
}
|
||||
@@ -435,7 +432,7 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
|
||||
assert(d->_root);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* stateDesc, desc->getChildren("state")) {
|
||||
for (auto stateDesc : desc->getChildren("state")) {
|
||||
std::string nm = stateDesc->getStringValue("name");
|
||||
State_ptr st(new State(nm));
|
||||
|
||||
@@ -446,7 +443,7 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
|
||||
addState(st);
|
||||
} // of states iteration
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* tDesc, desc->getChildren("transition")) {
|
||||
for (auto tDesc : desc->getChildren("transition")) {
|
||||
std::string nm = tDesc->getStringValue("name");
|
||||
State_ptr target = findStateByName(tDesc->getStringValue("target"));
|
||||
|
||||
@@ -456,7 +453,7 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
|
||||
t->setTriggerCondition(cond);
|
||||
|
||||
t->setExcludeTarget(tDesc->getBoolValue("exclude-target", true));
|
||||
BOOST_FOREACH(SGPropertyNode* src, tDesc->getChildren("source")) {
|
||||
for (auto src : tDesc->getChildren("source")) {
|
||||
State_ptr srcState = findStateByName(src->getStringValue());
|
||||
t->addSourceState(srcState);
|
||||
}
|
||||
|
||||
@@ -212,15 +212,23 @@ void testBindings()
|
||||
|
||||
void testParse()
|
||||
{
|
||||
const char* xml = "<?xml version=\"1.0\"?>"
|
||||
"<PropertyList>"
|
||||
"<state>"
|
||||
"<name>one</name>"
|
||||
"</state>"
|
||||
"<state>"
|
||||
"<name>two</name>"
|
||||
"</state>"
|
||||
"</PropertyList>";
|
||||
const char* xml = R"(<?xml version="1.0"?>
|
||||
<PropertyList>
|
||||
<state>
|
||||
<name>one</name>
|
||||
<enter>
|
||||
<command>nasal</command>
|
||||
<script>print('Foo');</script>
|
||||
</enter>
|
||||
<exit>
|
||||
<command>nasal</command>
|
||||
<script>print('bar');</script>
|
||||
</exit>
|
||||
</state>
|
||||
<state>
|
||||
<name>two</name>
|
||||
</state>
|
||||
</PropertyList>)";
|
||||
|
||||
SGPropertyNode* desc = new SGPropertyNode;
|
||||
readProperties(xml, strlen(xml), desc);
|
||||
|
||||
Reference in New Issue
Block a user