Compare commits
66 Commits
version/3.
...
version/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7598df4d3 | ||
|
|
63e7a1fbb4 | ||
|
|
951859d8a7 | ||
|
|
41f40a9a10 | ||
|
|
a6290e367a | ||
|
|
af0a51930e | ||
|
|
ccb5d05eb4 | ||
|
|
9d7402242a | ||
|
|
819833a560 | ||
|
|
576ff21488 | ||
|
|
b60f8b4989 | ||
|
|
096d625445 | ||
|
|
dad77b3983 | ||
|
|
598b64fa95 | ||
|
|
b5d6aa3fe4 | ||
|
|
f32063e6dd | ||
|
|
3d9d44cf73 | ||
|
|
ac84115ac3 | ||
|
|
d58607242e | ||
|
|
7afd2be652 | ||
|
|
f256d45b65 | ||
|
|
edf15e9f55 | ||
|
|
2bb24f43fb | ||
|
|
be0447d4c0 | ||
|
|
ef7a0dc5a3 | ||
|
|
5d754c0419 | ||
|
|
1f23fb89c0 | ||
|
|
584ee1364f | ||
|
|
1e32c24a17 | ||
|
|
20ea55bdbc | ||
|
|
c62b4467b4 | ||
|
|
31095c39cc | ||
|
|
05d9d7cae8 | ||
|
|
78a548b861 | ||
|
|
6be4ad27ee | ||
|
|
589c5ba35a | ||
|
|
81d668784a | ||
|
|
75ad5a7e5c | ||
|
|
3f20a3d2c6 | ||
|
|
a57e969639 | ||
|
|
23b8c86e78 | ||
|
|
5c9ca9cbe2 | ||
|
|
5676f96fbf | ||
|
|
4104f7d18f | ||
|
|
10e6bbc2c5 | ||
|
|
21e6dd34b2 | ||
|
|
319922f044 | ||
|
|
ff3efaee93 | ||
|
|
08fb433923 | ||
|
|
1a752d28a4 | ||
|
|
00a20409f7 | ||
|
|
3bfd0c872a | ||
|
|
945cf5d963 | ||
|
|
4e40913aef | ||
|
|
3bc53474ed | ||
|
|
28dff1d5ca | ||
|
|
81bfec336c | ||
|
|
60a0c51e2b | ||
|
|
70c5d60564 | ||
|
|
1b2247103a | ||
|
|
a49c3a49d3 | ||
|
|
105438fc58 | ||
|
|
2910c6a77b | ||
|
|
6dd859c75e | ||
|
|
b7c7f66bf3 | ||
|
|
c7a60d4dc4 |
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required (VERSION 2.6.4)
|
||||
cmake_minimum_required (VERSION 2.8.11)
|
||||
|
||||
if(COMMAND cmake_policy)
|
||||
if(POLICY CMP0054)
|
||||
@@ -14,10 +14,10 @@ include (CheckIncludeFile)
|
||||
include (CheckLibraryExists)
|
||||
include (CheckCXXSourceCompiles)
|
||||
include (CheckCXXCompilerFlag)
|
||||
include (GenerateExportHeader)
|
||||
|
||||
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
|
||||
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk)
|
||||
|
||||
# only relevant for building shared libs but let's set it regardless
|
||||
set(CMAKE_OSX_RPATH 1)
|
||||
@@ -80,12 +80,7 @@ endif(NOT CMAKE_BUILD_TYPE)
|
||||
# Determine name of library installation directory, i.e. "lib" vs "lib64", which
|
||||
# differs between all Debian-based vs all other Linux distros.
|
||||
# See cmake bug #11964, http://cmake.org/gitweb?p=cmake.git;a=commit;h=126c993d
|
||||
# GNUInstallDirs requires CMake >= 2.8.5, use own file for older cmake
|
||||
if(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(GNUInstallDirs)
|
||||
else(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(OldGNUInstallDirs)
|
||||
endif(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(GNUInstallDirs)
|
||||
message(STATUS "Library installation directory: ${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
#####################################################################################
|
||||
@@ -122,6 +117,7 @@ option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF)
|
||||
option(ENABLE_TESTS "Set to OFF to disable building SimGear's test applications" ON)
|
||||
option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" ON)
|
||||
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
|
||||
option(ENABLE_CURL "Set to ON to use libCurl as the HTTP client backend" OFF)
|
||||
|
||||
if (MSVC)
|
||||
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
|
||||
@@ -179,6 +175,11 @@ endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||
|
||||
if(APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
|
||||
# this should be handled by setting CMAKE_OSX_DEPLOYMENT_TARGET
|
||||
# but it's not working reliably, so forcing it for now
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.7")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR
|
||||
@@ -209,6 +210,11 @@ endif(SIMGEAR_HEADLESS)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
if (ENABLE_CURL)
|
||||
find_package(CURL REQUIRED)
|
||||
message(STATUS "Curl HTTP client: ENABLED")
|
||||
endif()
|
||||
|
||||
if (SYSTEM_EXPAT)
|
||||
message(STATUS "Requested to use system Expat library, forcing SIMGEAR_SHARED to true")
|
||||
set(SIMGEAR_SHARED ON)
|
||||
@@ -374,6 +380,7 @@ include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${CURL_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
@@ -402,7 +409,8 @@ set(TEST_LIBS_INTERNAL_CORE
|
||||
${WINSOCK_LIBRARY}
|
||||
${RT_LIBRARY}
|
||||
${DL_LIBRARY}
|
||||
${COCOA_LIBRARY})
|
||||
${COCOA_LIBRARY}
|
||||
${CURL_LIBRARIES})
|
||||
set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
@@ -416,6 +424,40 @@ include_directories(3rdparty/utf8/source)
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(simgear)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
### Export stuff, see https://cmake.org/cmake/help/v3.2/manual/cmake-packages.7.html#creating-packages
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
generate_export_header(SimGearCore)
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
generate_export_header(SimGearScene)
|
||||
endif()
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
|
||||
VERSION ${SIMGEAR_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
configure_file(SimGearConfig.cmake.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set(ConfigPackageLocation lib/cmake/SimGear)
|
||||
install(EXPORT SimGearTargets
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
### uninstall target
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -425,5 +467,3 @@ CONFIGURE_FILE(
|
||||
IMMEDIATE @ONLY)
|
||||
ADD_CUSTOM_TARGET(uninstall
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
# - Define GNU standard installation directories
|
||||
# Provides install directory variables as defined for GNU software:
|
||||
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||
# Inclusion of this module defines the following variables:
|
||||
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
# where <dir> is one of:
|
||||
# BINDIR - user executables (bin)
|
||||
# SBINDIR - system admin executables (sbin)
|
||||
# LIBEXECDIR - program executables (libexec)
|
||||
# SYSCONFDIR - read-only single-machine data (etc)
|
||||
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||
# LIBDIR - object code libraries (lib or lib64)
|
||||
# INCLUDEDIR - C header files (include)
|
||||
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
|
||||
# install() commands for the corresponding file type. If the includer does
|
||||
# not define a value the above-shown default will be used and the value will
|
||||
# appear in the cache for editing by the user.
|
||||
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||
# from the corresponding destination by prepending (if necessary) the value
|
||||
# of CMAKE_INSTALL_PREFIX.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Installation directories
|
||||
#
|
||||
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(_LIBDIR_DEFAULT "lib")
|
||||
# Override this default 'lib' with 'lib64' iff:
|
||||
# - we are on Linux system but NOT cross-compiling
|
||||
# - we are NOT on debian
|
||||
# - we are on a 64 bits system
|
||||
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||
# Note that the future of multi-arch handling may be even
|
||||
# more complicated than that: http://wiki.debian.org/Multiarch
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||
AND NOT CMAKE_CROSSCOMPILING
|
||||
AND NOT EXISTS "/etc/debian_version")
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
message(AUTHOR_WARNING
|
||||
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||
"Please enable at least one language before including GNUInstallDirs.")
|
||||
else()
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_LIBDIR_DEFAULT "lib64")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||
# the cache and store the defaults in local variables if the cache values are
|
||||
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||
|
||||
if(NOT CMAKE_INSTALL_DATADIR)
|
||||
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_INFODIR)
|
||||
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_MANDIR)
|
||||
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_INSTALL_BINDIR
|
||||
CMAKE_INSTALL_SBINDIR
|
||||
CMAKE_INSTALL_LIBEXECDIR
|
||||
CMAKE_INSTALL_SYSCONFDIR
|
||||
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||
CMAKE_INSTALL_LOCALSTATEDIR
|
||||
CMAKE_INSTALL_LIBDIR
|
||||
CMAKE_INSTALL_INCLUDEDIR
|
||||
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||
CMAKE_INSTALL_DATAROOTDIR
|
||||
CMAKE_INSTALL_DATADIR
|
||||
CMAKE_INSTALL_INFODIR
|
||||
CMAKE_INSTALL_LOCALEDIR
|
||||
CMAKE_INSTALL_MANDIR
|
||||
CMAKE_INSTALL_DOCDIR
|
||||
)
|
||||
|
||||
# Result directories
|
||||
#
|
||||
foreach(dir
|
||||
BINDIR
|
||||
SBINDIR
|
||||
LIBEXECDIR
|
||||
SYSCONFDIR
|
||||
SHAREDSTATEDIR
|
||||
LOCALSTATEDIR
|
||||
LIBDIR
|
||||
INCLUDEDIR
|
||||
OLDINCLUDEDIR
|
||||
DATAROOTDIR
|
||||
DATADIR
|
||||
INFODIR
|
||||
LOCALEDIR
|
||||
MANDIR
|
||||
DOCDIR
|
||||
)
|
||||
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||
endif()
|
||||
endforeach()
|
||||
16
SimGearConfig.cmake.in
Normal file
16
SimGearConfig.cmake.in
Normal file
@@ -0,0 +1,16 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(ZLIB)
|
||||
find_dependency(Threads)
|
||||
|
||||
# OSG
|
||||
|
||||
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
|
||||
set(SIMGEAR_SOUND @ENABLE_SOUND@)
|
||||
|
||||
# OpenAL isn't a public dependency, so maybe not needed
|
||||
#if (SIMGEAR_SOUND)
|
||||
# find_dependency(OpenAL)
|
||||
#endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/SimGearTargets.cmake")
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
file(WRITE ${PROJECT_BINARY_DIR}/simgear/version.h "#define SIMGEAR_VERSION ${SIMGEAR_VERSION}")
|
||||
|
||||
foreach( mylibfolder
|
||||
foreach( mylibfolder
|
||||
bucket
|
||||
bvh
|
||||
debug
|
||||
@@ -54,9 +54,11 @@ if(SIMGEAR_SHARED)
|
||||
set_property(TARGET SimGearCore PROPERTY LINKER_LANGUAGE CXX)
|
||||
set_property(TARGET SimGearCore PROPERTY VERSION ${SIMGEAR_VERSION})
|
||||
set_property(TARGET SimGearCore PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
|
||||
install(TARGETS SimGearCore EXPORT SimGearCoreConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(EXPORT SimGearCoreConfig DESTINATION share/SimGearCore)
|
||||
|
||||
install(TARGETS SimGearCore
|
||||
EXPORT SimGearTargets
|
||||
LIBRARY DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
add_library(SimGearScene SHARED ${sceneSources})
|
||||
set_property(TARGET SimGearScene PROPERTY LINKER_LANGUAGE CXX)
|
||||
@@ -64,10 +66,12 @@ if(SIMGEAR_SHARED)
|
||||
set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
|
||||
|
||||
# EXPORT SimGearSceneConfig
|
||||
install(TARGETS SimGearScene LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} )
|
||||
# install(EXPORT SimGearSceneConfig DESTINATION share/SimGearScene)
|
||||
install(TARGETS SimGearScene
|
||||
EXPORT SimGearTargets
|
||||
LIBRARY
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR} )
|
||||
endif()
|
||||
|
||||
|
||||
else()
|
||||
message(STATUS "Library building mode: STATIC LIBRARIES")
|
||||
|
||||
@@ -90,8 +94,10 @@ else()
|
||||
endforeach()
|
||||
|
||||
add_library(SimGearCore STATIC ${coreSources} ${localExpatSources})
|
||||
install(TARGETS SimGearCore ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
install(TARGETS SimGearCore
|
||||
EXPORT SimGearTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
get_property(FG_GROUPS_SCENE_SOURCES_C GLOBAL PROPERTY FG_GROUPS_SCENE_SOURCES_C)
|
||||
string(REPLACE "@" ";" groups ${FG_GROUPS_SCENE_SOURCES_C} )
|
||||
@@ -112,7 +118,9 @@ else()
|
||||
endforeach()
|
||||
|
||||
add_library(SimGearScene STATIC ${sceneSources})
|
||||
install(TARGETS SimGearScene ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(TARGETS SimGearScene
|
||||
EXPORT SimGearTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif(NOT SIMGEAR_HEADLESS)
|
||||
endif(SIMGEAR_SHARED)
|
||||
|
||||
@@ -122,7 +130,8 @@ target_link_libraries(SimGearCore
|
||||
${DL_LIBRARY}
|
||||
${EXPAT_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${COCOA_LIBRARY})
|
||||
${COCOA_LIBRARY}
|
||||
${CURL_LIBRARIES})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
target_link_libraries(SimGearScene
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
void removeChild(BVHNode* child);
|
||||
|
||||
unsigned getNumChildren() const
|
||||
{ return _children.size(); }
|
||||
{ return static_cast<unsigned>(_children.size()); }
|
||||
const BVHNode* getChild(unsigned i) const
|
||||
{ if (_children.size() <= i) return 0; return _children[i]; }
|
||||
BVHNode* getChild(unsigned i)
|
||||
|
||||
@@ -31,13 +31,13 @@ public:
|
||||
virtual ~BVHStaticData() {}
|
||||
|
||||
unsigned addVertex(const SGVec3f& vertex)
|
||||
{ _vertices.push_back(vertex); return _vertices.size() - 1; }
|
||||
{ _vertices.push_back(vertex); return static_cast<unsigned>(_vertices.size() - 1); }
|
||||
const SGVec3f& getVertex(unsigned i) const
|
||||
{ return _vertices[i]; }
|
||||
|
||||
|
||||
unsigned addMaterial(const BVHMaterial* material)
|
||||
{ _materials.push_back(material); return _materials.size() - 1; }
|
||||
{ _materials.push_back(material); return static_cast<unsigned>(_materials.size() - 1); }
|
||||
const BVHMaterial* getMaterial(unsigned i) const
|
||||
{ if (_materials.size() <= i) return 0; return _materials[i]; }
|
||||
|
||||
|
||||
@@ -207,19 +207,6 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
Element::~Element()
|
||||
{
|
||||
if( !_transform.valid() )
|
||||
return;
|
||||
|
||||
for(unsigned int i = 0; i < _transform->getNumChildren(); ++i)
|
||||
{
|
||||
OSGUserData* ud =
|
||||
static_cast<OSGUserData*>(_transform->getChild(i)->getUserData());
|
||||
|
||||
if( ud )
|
||||
// Ensure parent is cleared to prevent accessing released memory if an
|
||||
// element somehow survives longer than his parent.
|
||||
ud->element->_parent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -246,7 +233,7 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
ElementPtr Element::getParent() const
|
||||
{
|
||||
return _parent;
|
||||
return _parent.lock();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -324,8 +311,9 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::ascend(EventVisitor& visitor)
|
||||
{
|
||||
if( _parent )
|
||||
return _parent->accept(visitor);
|
||||
ElementPtr parent = getParent();
|
||||
if( parent )
|
||||
return parent->accept(visitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -374,9 +362,9 @@ namespace canvas
|
||||
EventPropagationPath path;
|
||||
path.push_back( EventTarget(this) );
|
||||
|
||||
for( Element* parent = _parent;
|
||||
parent != NULL;
|
||||
parent = parent->_parent )
|
||||
for( ElementPtr parent = getParent();
|
||||
parent.valid();
|
||||
parent = parent->getParent() )
|
||||
path.push_front( EventTarget(parent) );
|
||||
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
@@ -772,7 +760,7 @@ namespace canvas
|
||||
Element::Element( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
PropertyBasedElement(node),
|
||||
_canvas( canvas ),
|
||||
_parent( parent ),
|
||||
@@ -871,11 +859,12 @@ namespace canvas
|
||||
Element::getParentStyle(const SGPropertyNode* child) const
|
||||
{
|
||||
// Try to get value from parent...
|
||||
if( _parent )
|
||||
ElementPtr parent = getParent();
|
||||
if( parent )
|
||||
{
|
||||
Style::const_iterator style =
|
||||
_parent->_style.find(child->getNameString());
|
||||
if( style != _parent->_style.end() )
|
||||
parent->_style.find(child->getNameString());
|
||||
if( style != parent->_style.end() )
|
||||
return style->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -232,8 +232,8 @@ namespace canvas
|
||||
|
||||
class RelativeScissor;
|
||||
|
||||
CanvasWeakPtr _canvas;
|
||||
Element *_parent;
|
||||
CanvasWeakPtr _canvas;
|
||||
ElementWeakPtr _parent;
|
||||
|
||||
mutable uint32_t _attributes_dirty;
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace canvas
|
||||
Element( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent );
|
||||
ElementWeakPtr parent );
|
||||
|
||||
/**
|
||||
* Returns false on first call and true on any successive call. Use to
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace canvas
|
||||
Group::Group( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent)
|
||||
{
|
||||
staticInit();
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace canvas
|
||||
Group( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style = Style(),
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Group();
|
||||
|
||||
ElementPtr createChild( const std::string& type,
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace canvas
|
||||
Image::Image( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_texture(new osg::Texture2D),
|
||||
_node_src_rect( node->getNode("source", 0, true) ),
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace canvas
|
||||
Image( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style = Style(),
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Image();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace canvas
|
||||
Map::Map( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Group(canvas, node, parent_style, parent),
|
||||
// TODO make projection configurable
|
||||
_projection(new SansonFlamsteedProjection),
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace canvas
|
||||
Map( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Map();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
@@ -531,7 +531,7 @@ namespace canvas
|
||||
Path::Path( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_path( new PathDrawable(this) )
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace canvas
|
||||
Path( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Path();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
@@ -740,7 +740,7 @@ namespace canvas
|
||||
Text::Text( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_text( new Text::TextOSG(this) )
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace canvas
|
||||
Text( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
~Text();
|
||||
|
||||
void setText(const char* text);
|
||||
|
||||
@@ -190,6 +190,12 @@ inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
|
||||
# define DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# define SG_NO_RETURN [[noreturn]]
|
||||
#else
|
||||
# define SG_NO_RETURN
|
||||
#endif
|
||||
|
||||
//
|
||||
// No user modifiable definitions beyond here.
|
||||
//
|
||||
|
||||
@@ -32,7 +32,8 @@ typedef enum {
|
||||
SG_SOUND = 0x00200000,
|
||||
SG_NAVAID = 0x00400000,
|
||||
SG_GUI = 0x00800000,
|
||||
SG_UNDEFD = 0x01000000, // For range checking
|
||||
SG_TERRASYNC = 0x01000000,
|
||||
SG_UNDEFD = 0x02000000, // For range checking
|
||||
|
||||
SG_ALL = 0xFFFFFFFF
|
||||
} sgDebugClass;
|
||||
|
||||
@@ -71,6 +71,7 @@ const char* debugClassToString(sgDebugClass c)
|
||||
case SG_SOUND: return "sound";
|
||||
case SG_NAVAID: return "navaid";
|
||||
case SG_GUI: return "gui";
|
||||
case SG_TERRASYNC: return "terrasync";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
bool load( const SGPath& path );
|
||||
|
||||
// stars
|
||||
inline int getNumStars() const { return _stars.size(); }
|
||||
inline int getNumStars() const { return static_cast<int>(_stars.size()); }
|
||||
inline SGVec3d *getStars() { return &(_stars[0]); }
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,7 +18,6 @@ set(HEADERS
|
||||
HTTPFileRequest.hxx
|
||||
HTTPMemoryRequest.hxx
|
||||
HTTPRequest.hxx
|
||||
HTTPContentDecode.hxx
|
||||
DAVMultiStatus.hxx
|
||||
SVNRepository.hxx
|
||||
SVNDirectory.hxx
|
||||
@@ -41,13 +40,17 @@ set(SOURCES
|
||||
HTTPFileRequest.cxx
|
||||
HTTPMemoryRequest.cxx
|
||||
HTTPRequest.cxx
|
||||
HTTPContentDecode.cxx
|
||||
DAVMultiStatus.cxx
|
||||
SVNRepository.cxx
|
||||
SVNDirectory.cxx
|
||||
SVNReportParser.cxx
|
||||
)
|
||||
|
||||
if (NOT ENABLE_CURL)
|
||||
list(APPEND SOURCES HTTPContentDecode.cxx)
|
||||
list(APPEND HEADERS HTTPContentDecode.hxx)
|
||||
endif()
|
||||
|
||||
simgear_component(io io "${SOURCES}" "${HEADERS}")
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
@@ -70,8 +73,8 @@ add_executable(decode_binobj decode_binobj.cxx)
|
||||
target_link_libraries(decode_binobj ${TEST_LIBS})
|
||||
|
||||
add_executable(test_binobj test_binobj.cxx)
|
||||
target_link_libraries(test_binobj ${TEST_LIBS})
|
||||
|
||||
target_link_libraries(test_binobj ${TEST_LIBS})
|
||||
|
||||
add_test(binobj ${EXECUTABLE_OUTPUT_PATH}/test_binobj)
|
||||
|
||||
endif(ENABLE_TESTS)
|
||||
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
{
|
||||
if (tagStack.empty()) {
|
||||
if (strcmp(name, DAV_MULTISTATUS_TAG)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "root element is not " <<
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "root element is not " <<
|
||||
DAV_MULTISTATUS_TAG << ", got:" << name);
|
||||
} else {
|
||||
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
// not at the root element
|
||||
if (tagStack.back() == DAV_MULTISTATUS_TAG) {
|
||||
if (strcmp(name, DAV_RESPONSE_TAG)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "multistatus child is not response: saw:"
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "multistatus child is not response: saw:"
|
||||
<< name);
|
||||
}
|
||||
}
|
||||
@@ -362,7 +362,7 @@ void DAVMultiStatus::parseXML(const char* data, int size)
|
||||
}
|
||||
|
||||
if (!XML_Parse(_d->xmlParser, data, size, false)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
|
||||
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
|
||||
|
||||
@@ -376,7 +376,7 @@ void DAVMultiStatus::finishParse()
|
||||
{
|
||||
if (_d->parserInited) {
|
||||
if (!XML_Parse(_d->xmlParser, NULL, 0, true)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
|
||||
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
|
||||
_d->valid = false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,15 +38,15 @@ namespace HTTP
|
||||
|
||||
// forward decls
|
||||
class Connection;
|
||||
|
||||
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
Client();
|
||||
~Client();
|
||||
|
||||
|
||||
void update(int waitTimeout = 0);
|
||||
|
||||
|
||||
void makeRequest(const Request_ptr& r);
|
||||
|
||||
/**
|
||||
@@ -68,44 +68,51 @@ public:
|
||||
|
||||
void setUserAgent(const std::string& ua);
|
||||
void setProxy(const std::string& proxy, int port, const std::string& auth = "");
|
||||
|
||||
|
||||
/**
|
||||
* Specify the maximum permitted simultaneous connections
|
||||
* (default value is 1)
|
||||
*/
|
||||
void setMaxConnections(unsigned int maxCons);
|
||||
|
||||
|
||||
const std::string& userAgent() const;
|
||||
|
||||
|
||||
const std::string& proxyHost() const;
|
||||
|
||||
|
||||
const std::string& proxyAuth() const;
|
||||
|
||||
|
||||
/**
|
||||
* predicate, check if at least one connection is active, with at
|
||||
* least one request active or queued.
|
||||
*/
|
||||
bool hasActiveRequests() const;
|
||||
|
||||
|
||||
/**
|
||||
* crude tracking of bytes-per-second transferred over the socket.
|
||||
* suitable for user feedback and rough profiling, nothing more.
|
||||
*/
|
||||
unsigned int transferRateBytesPerSec() const;
|
||||
|
||||
|
||||
/**
|
||||
* total bytes downloaded by this HTTP client, for bandwidth usage
|
||||
* monitoring
|
||||
*/
|
||||
uint64_t totalBytesDownloaded() const;
|
||||
|
||||
void debugDumpRequests();
|
||||
private:
|
||||
// libCurl callbacks
|
||||
static size_t requestWriteCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
|
||||
static size_t requestReadCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
|
||||
static size_t requestHeaderCallback(char *buffer, size_t size, size_t nitems, void *userdata);
|
||||
|
||||
void requestFinished(Connection* con);
|
||||
|
||||
|
||||
void receivedBytes(unsigned int count);
|
||||
|
||||
|
||||
friend class Connection;
|
||||
friend class Request;
|
||||
|
||||
|
||||
class ClientPrivate;
|
||||
std::auto_ptr<ClientPrivate> d;
|
||||
};
|
||||
|
||||
@@ -133,19 +133,25 @@ void Request::responseStart(const std::string& r)
|
||||
const int maxSplit = 2; // HTTP/1.1 nnn reason-string
|
||||
string_list parts = strutils::split(r, NULL, maxSplit);
|
||||
if (parts.size() != 3) {
|
||||
throw sg_io_exception("bad HTTP response");
|
||||
throw sg_io_exception("bad HTTP response:" + r);
|
||||
}
|
||||
|
||||
|
||||
_responseVersion = decodeHTTPVersion(parts[0]);
|
||||
_responseStatus = strutils::to_int(parts[1]);
|
||||
_responseReason = parts[2];
|
||||
|
||||
setReadyState(STATUS_RECEIVED);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Request::responseHeader(const std::string& key, const std::string& value)
|
||||
{
|
||||
if( key == "connection" )
|
||||
if( key == "connection" ) {
|
||||
_willClose = (value.find("close") != std::string::npos);
|
||||
} else if (key == "content-length") {
|
||||
int sz = strutils::to_int(value);
|
||||
setResponseLength(sz);
|
||||
}
|
||||
|
||||
_responseHeaders[key] = value;
|
||||
}
|
||||
@@ -207,7 +213,7 @@ std::string Request::scheme() const
|
||||
if (firstColon > 0) {
|
||||
return url().substr(0, firstColon);
|
||||
}
|
||||
|
||||
|
||||
return ""; // couldn't parse scheme
|
||||
}
|
||||
|
||||
@@ -219,20 +225,20 @@ std::string Request::path() const
|
||||
if (schemeEnd < 0) {
|
||||
return ""; // couldn't parse scheme
|
||||
}
|
||||
|
||||
|
||||
int hostEnd = u.find('/', schemeEnd + 3);
|
||||
if (hostEnd < 0) {
|
||||
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
|
||||
// fixup to root resource path: '/'
|
||||
return "/";
|
||||
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
|
||||
// fixup to root resource path: '/'
|
||||
return "/";
|
||||
}
|
||||
|
||||
|
||||
int query = u.find('?', hostEnd + 1);
|
||||
if (query < 0) {
|
||||
// all remainder of URL is path
|
||||
return u.substr(hostEnd);
|
||||
}
|
||||
|
||||
|
||||
return u.substr(hostEnd, query - hostEnd);
|
||||
}
|
||||
|
||||
@@ -244,7 +250,7 @@ std::string Request::query() const
|
||||
if (query < 0) {
|
||||
return ""; //no query string found
|
||||
}
|
||||
|
||||
|
||||
return u.substr(query); //includes question mark
|
||||
}
|
||||
|
||||
@@ -319,6 +325,7 @@ unsigned int Request::responseLength() const
|
||||
//------------------------------------------------------------------------------
|
||||
void Request::setFailure(int code, const std::string& reason)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_WARN, "HTTP request: set failure:" << code << " reason " << reason);
|
||||
_responseStatus = code;
|
||||
_responseReason = reason;
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
{
|
||||
UNSENT = 0,
|
||||
OPENED,
|
||||
STATUS_RECEIVED,
|
||||
HEADERS_RECEIVED,
|
||||
LOADING,
|
||||
DONE,
|
||||
@@ -124,19 +125,19 @@ public:
|
||||
void setBodyData( const SGPropertyNode* data );
|
||||
|
||||
virtual void setUrl(const std::string& url);
|
||||
|
||||
|
||||
virtual std::string method() const
|
||||
{ return _method; }
|
||||
virtual std::string url() const
|
||||
{ return _url; }
|
||||
|
||||
|
||||
virtual std::string scheme() const;
|
||||
virtual std::string path() const;
|
||||
virtual std::string host() const;
|
||||
virtual std::string hostAndPort() const;
|
||||
virtual unsigned short port() const;
|
||||
virtual std::string query() const;
|
||||
|
||||
|
||||
StringMap const& responseHeaders() const
|
||||
{ return _responseHeaders; }
|
||||
|
||||
@@ -144,13 +145,13 @@ public:
|
||||
|
||||
virtual int responseCode() const
|
||||
{ return _responseStatus; }
|
||||
|
||||
|
||||
virtual std::string responseReason() const
|
||||
{ return _responseReason; }
|
||||
|
||||
|
||||
void setResponseLength(unsigned int l);
|
||||
virtual unsigned int responseLength() const;
|
||||
|
||||
|
||||
/**
|
||||
* Check if request contains body data.
|
||||
*/
|
||||
@@ -165,32 +166,32 @@ public:
|
||||
* Retrieve the size of the request body.
|
||||
*/
|
||||
virtual size_t bodyLength() const;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the body data bytes. Will be passed the maximum body bytes
|
||||
* to return in the buffer, and must return the actual number
|
||||
* of bytes written.
|
||||
* of bytes written.
|
||||
*/
|
||||
virtual size_t getBodyData(char* s, size_t offset, size_t max_count) const;
|
||||
|
||||
|
||||
/**
|
||||
* running total of body bytes received so far. Can be used
|
||||
* to generate a completion percentage, if the response length is
|
||||
* known.
|
||||
* known.
|
||||
*/
|
||||
unsigned int responseBytesReceived() const
|
||||
{ return _receivedBodyBytes; }
|
||||
|
||||
|
||||
enum HTTPVersion {
|
||||
HTTP_VERSION_UNKNOWN = 0,
|
||||
HTTP_0_x, // 0.9 or similar
|
||||
HTTP_1_0,
|
||||
HTTP_1_1
|
||||
};
|
||||
|
||||
|
||||
HTTPVersion responseVersion() const
|
||||
{ return _responseVersion; }
|
||||
|
||||
|
||||
ReadyState readyState() const { return _ready_state; }
|
||||
|
||||
/**
|
||||
@@ -226,7 +227,7 @@ private:
|
||||
friend class Client;
|
||||
friend class Connection;
|
||||
friend class ContentDecoder;
|
||||
|
||||
|
||||
Request(const Request&); // = delete;
|
||||
Request& operator=(const Request&); // = delete;
|
||||
|
||||
|
||||
@@ -96,14 +96,14 @@ void SVNDirectory::parseCache()
|
||||
LineState lineState = LINESTATE_HREF;
|
||||
std::ifstream file(p.c_str());
|
||||
if (!file.is_open()) {
|
||||
SG_LOG(SG_IO, SG_WARN, "unable to open cache file for reading:" << p);
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "unable to open cache file for reading:" << p);
|
||||
return;
|
||||
}
|
||||
bool doneSelf = false;
|
||||
|
||||
file.getline(href, 1024);
|
||||
if (strcmp(CACHE_VERSION_4_TOKEN, href)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ void SVNDirectory::writeCache()
|
||||
void SVNDirectory::setBaseUrl(const string& url)
|
||||
{
|
||||
if (_parent) {
|
||||
SG_LOG(SG_IO, SG_ALERT, "setting base URL on non-root directory " << url);
|
||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "setting base URL on non-root directory " << url);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
|
||||
Dir d(path);
|
||||
bool ok = d.remove(true);
|
||||
if (!ok) {
|
||||
SG_LOG(SG_NETWORK, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove dir:"
|
||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove dir:"
|
||||
<< nm << " at path:\n\t" << path);
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
|
||||
} else {
|
||||
bool ok = path.remove();
|
||||
if (!ok) {
|
||||
SG_LOG(SG_NETWORK, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove path:" << nm
|
||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove path:" << nm
|
||||
<< " at path:\n\t" << path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
|
||||
void updateFailed(HTTP::Request* req, SVNRepository::ResultCode err)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_WARN, "SVN: failed to update from:" << req->url()
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: failed to update from:" << req->url()
|
||||
<< "\n(repository:" << p->baseUrl() << ")");
|
||||
isUpdating = false;
|
||||
status = err;
|
||||
@@ -120,6 +120,7 @@ namespace { // anonmouse
|
||||
Request(repo->baseUrl, "PROPFIND"),
|
||||
_repo(repo)
|
||||
{
|
||||
assert(repo);
|
||||
requestHeader("Depth") = "0";
|
||||
setBodyData( PROPFIND_REQUEST_BODY,
|
||||
"application/xml; charset=\"utf-8\"" );
|
||||
@@ -133,11 +134,13 @@ namespace { // anonmouse
|
||||
} else if (responseCode() == 404) {
|
||||
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
|
||||
} else {
|
||||
SG_LOG(SG_IO, SG_WARN, "request for:" << url() <<
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "request for:" << url() <<
|
||||
" return code " << responseCode());
|
||||
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_SOCKET);
|
||||
_repo = NULL;
|
||||
}
|
||||
|
||||
Request::responseHeadersComplete();
|
||||
}
|
||||
|
||||
virtual void onDone()
|
||||
@@ -228,7 +231,7 @@ protected:
|
||||
_repo->updateFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
|
||||
_failed = true;
|
||||
} else {
|
||||
SG_LOG(SG_IO, SG_WARN, "SVN: request for:" << url() <<
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: request for:" << url() <<
|
||||
" got HTTP status " << responseCode());
|
||||
_repo->updateFailed(this, SVNRepository::SVN_ERROR_HTTP);
|
||||
_failed = true;
|
||||
@@ -328,7 +331,7 @@ void SVNRepository::update()
|
||||
}
|
||||
|
||||
if (_d->targetRevision == rootDir()->cachedRevision()) {
|
||||
SG_LOG(SG_IO, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
|
||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
|
||||
_d->isUpdating = false;
|
||||
return;
|
||||
}
|
||||
@@ -372,7 +375,7 @@ void SVNRepoPrivate::propFindComplete(HTTP::Request* req, DAVCollection* c)
|
||||
void SVNRepoPrivate::propFindFailed(HTTP::Request *req, SVNRepository::ResultCode err)
|
||||
{
|
||||
if (err != SVNRepository::SVN_ERROR_NOT_FOUND) {
|
||||
SG_LOG(SG_IO, SG_WARN, "PropFind failed for:" << req->url());
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "PropFind failed for:" << req->url());
|
||||
}
|
||||
|
||||
isUpdating = false;
|
||||
|
||||
@@ -227,6 +227,13 @@ void NetChannel::handleAccept (void) {
|
||||
|
||||
void NetChannel::handleError (int error)
|
||||
{
|
||||
if (error == EINPROGRESS) {
|
||||
// this shoudl never happen, because we should use isNonBlocking to check
|
||||
// such error codes.
|
||||
SG_LOG(SG_IO, SG_WARN, "Got EINPROGRESS at NetChannel::handleError: suggests broken logic somewhere else");
|
||||
return; // not an actual error, don't warn
|
||||
}
|
||||
|
||||
// warn about address lookup failures seperately, don't warn again.
|
||||
// (and we (ab-)use ENOENT to mean 'name not found'.
|
||||
if (error != ENOENT) {
|
||||
|
||||
@@ -3,15 +3,23 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <errno.h>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include <simgear/simgear_config.h>
|
||||
|
||||
#include "HTTPClient.hxx"
|
||||
#include "HTTPRequest.hxx"
|
||||
|
||||
#include <simgear/io/sg_netChat.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
#include <curl/multi.h>
|
||||
#endif
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
@@ -46,7 +54,7 @@ char body2[body2Size];
|
||||
cerr << "failed:" << #a << endl; \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
|
||||
class TestRequest : public HTTP::Request
|
||||
{
|
||||
public:
|
||||
@@ -54,41 +62,43 @@ public:
|
||||
bool failed;
|
||||
string bodyData;
|
||||
|
||||
TestRequest(const std::string& url, const std::string method = "GET") :
|
||||
TestRequest(const std::string& url, const std::string method = "GET") :
|
||||
HTTP::Request(url, method),
|
||||
complete(false)
|
||||
complete(false),
|
||||
failed(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::map<string, string> headers;
|
||||
protected:
|
||||
|
||||
|
||||
virtual void onDone()
|
||||
{
|
||||
complete = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
virtual void onFail()
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
|
||||
|
||||
virtual void gotBodyData(const char* s, int n)
|
||||
{
|
||||
//std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
|
||||
bodyData += string(s, n);
|
||||
}
|
||||
|
||||
|
||||
virtual void responseHeader(const string& header, const string& value)
|
||||
{
|
||||
Request::responseHeader(header, value);
|
||||
headers[header] = value;
|
||||
}
|
||||
};
|
||||
|
||||
class TestServerChannel : public NetChat
|
||||
{
|
||||
public:
|
||||
public:
|
||||
enum State
|
||||
{
|
||||
STATE_IDLE = 0,
|
||||
@@ -96,19 +106,19 @@ public:
|
||||
STATE_CLOSING,
|
||||
STATE_REQUEST_BODY
|
||||
};
|
||||
|
||||
|
||||
TestServerChannel()
|
||||
{
|
||||
state = STATE_IDLE;
|
||||
setTerminator("\r\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
virtual void collectIncomingData(const char* s, int n)
|
||||
{
|
||||
buffer += string(s, n);
|
||||
}
|
||||
|
||||
|
||||
virtual void foundTerminator(void)
|
||||
{
|
||||
if (state == STATE_IDLE) {
|
||||
@@ -118,16 +128,16 @@ public:
|
||||
cerr << "malformed request:" << buffer << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
method = line[0];
|
||||
path = line[1];
|
||||
|
||||
|
||||
string::size_type queryPos = path.find('?');
|
||||
if (queryPos != string::npos) {
|
||||
parseArgs(path.substr(queryPos + 1));
|
||||
path = path.substr(0, queryPos);
|
||||
}
|
||||
|
||||
|
||||
httpVersion = line[2];
|
||||
requestHeaders.clear();
|
||||
buffer.clear();
|
||||
@@ -138,10 +148,10 @@ public:
|
||||
receivedRequestHeaders();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string::size_type colonPos = buffer.find(':');
|
||||
if (colonPos == string::npos) {
|
||||
cerr << "malformed HTTP response header:" << buffer << endl;
|
||||
cerr << "test malformed HTTP response header:" << buffer << endl;
|
||||
buffer.clear();
|
||||
return;
|
||||
}
|
||||
@@ -156,8 +166,8 @@ public:
|
||||
} else if (state == STATE_CLOSING) {
|
||||
// ignore!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void parseArgs(const string& argData)
|
||||
{
|
||||
string_list argv = strutils::split(argData, "&");
|
||||
@@ -173,11 +183,10 @@ public:
|
||||
args[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void receivedRequestHeaders()
|
||||
{
|
||||
state = STATE_IDLE;
|
||||
|
||||
if (path == "/test1") {
|
||||
string contentStr(BODY1);
|
||||
stringstream d;
|
||||
@@ -205,7 +214,7 @@ public:
|
||||
} else if (path == "/test_headers") {
|
||||
COMPARE(requestHeaders["X-Foo"], string("Bar"));
|
||||
COMPARE(requestHeaders["X-AnotherHeader"], string("A longer value"));
|
||||
|
||||
|
||||
string contentStr(BODY1);
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
|
||||
@@ -235,11 +244,11 @@ public:
|
||||
if (requestHeaders["Host"] != "www.google.com") {
|
||||
sendErrorResponse(400, true, "bad destination");
|
||||
}
|
||||
|
||||
|
||||
if (requestHeaders["Proxy-Authorization"] != string()) {
|
||||
sendErrorResponse(401, false, "bad auth"); // shouldn't supply auth
|
||||
sendErrorResponse(401, false, "bad auth, not empty"); // shouldn't supply auth
|
||||
}
|
||||
|
||||
|
||||
sendBody2();
|
||||
} else if (path == "http://www.google.com/test3") {
|
||||
// proxy test
|
||||
@@ -247,8 +256,28 @@ public:
|
||||
sendErrorResponse(400, true, "bad destination");
|
||||
}
|
||||
|
||||
if (requestHeaders["Proxy-Authorization"] != "ABCDEF") {
|
||||
sendErrorResponse(401, false, "bad auth"); // forbidden
|
||||
string credentials = requestHeaders["Proxy-Authorization"];
|
||||
if (credentials.substr(0, 5) != "Basic") {
|
||||
// request basic auth
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 407 << " " << reasonForCode(407) << "\r\n";
|
||||
d << "WWW-Authenticate: Basic real=\"simgear\"\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
push(d.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> userAndPass;
|
||||
strutils::decodeBase64(credentials.substr(6), userAndPass);
|
||||
std::string decodedUserPass((char*) userAndPass.data(), userAndPass.size());
|
||||
|
||||
if (decodedUserPass != "johndoe:swordfish") {
|
||||
std::map<string, string>::const_iterator it;
|
||||
for (it = requestHeaders.begin(); it != requestHeaders.end(); ++it) {
|
||||
cerr << "header:" << it->first << " = " << it->second << endl;
|
||||
}
|
||||
|
||||
sendErrorResponse(401, false, "bad auth, not as set"); // forbidden
|
||||
}
|
||||
|
||||
sendBody2();
|
||||
@@ -272,6 +301,12 @@ public:
|
||||
d << contentStr;
|
||||
push(d.str().c_str());
|
||||
closeAfterSending();
|
||||
} else if (path == "/test_abrupt_close") {
|
||||
// simulate server doing socket close before sending any
|
||||
// response - this used to cause a TerraSync failure since we
|
||||
// would get stuck restarting the request
|
||||
closeAfterSending();
|
||||
|
||||
} else if (path == "/test_args") {
|
||||
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
|
||||
sendErrorResponse(400, true, "bad arguments");
|
||||
@@ -291,43 +326,78 @@ public:
|
||||
sendErrorResponse(400, true, "bad content type");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
|
||||
setByteCount(requestContentLength);
|
||||
state = STATE_REQUEST_BODY;
|
||||
} else if ((path == "/test_put") || (path == "/test_create")) {
|
||||
if (requestHeaders["Content-Type"] != "x-application/foobar") {
|
||||
cerr << "bad content type: '" << requestHeaders["Content-Type"] << "'" << endl;
|
||||
sendErrorResponse(400, true, "bad content type");
|
||||
return;
|
||||
}
|
||||
|
||||
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
|
||||
setByteCount(requestContentLength);
|
||||
state = STATE_REQUEST_BODY;
|
||||
} else {
|
||||
sendErrorResponse(404, false, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void closeAfterSending()
|
||||
{
|
||||
state = STATE_CLOSING;
|
||||
closeWhenDone();
|
||||
}
|
||||
|
||||
|
||||
void receivedBody()
|
||||
{
|
||||
state = STATE_IDLE;
|
||||
if (method == "POST") {
|
||||
parseArgs(buffer);
|
||||
}
|
||||
|
||||
|
||||
if (path == "/test_post") {
|
||||
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
|
||||
sendErrorResponse(400, true, "bad arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
push(d.str().c_str());
|
||||
|
||||
cerr << "sent 204 response ok" << endl;
|
||||
} else if (path == "/test_put") {
|
||||
std::cerr << "sending PUT response" << std::endl;
|
||||
|
||||
COMPARE(buffer, BODY3);
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
push(d.str().c_str());
|
||||
} else if (path == "/test_create") {
|
||||
std::cerr << "sending create response" << std::endl;
|
||||
|
||||
std::string entityStr = "http://localhost:2000/something.txt";
|
||||
|
||||
COMPARE(buffer, BODY3);
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 201 << " " << reasonForCode(201) << "\r\n";
|
||||
d << "Location:" << entityStr << "\r\n";
|
||||
d << "Content-Length:" << entityStr.size() << "\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
d << entityStr;
|
||||
|
||||
push(d.str().c_str());
|
||||
} else {
|
||||
std::cerr << "weird URL " << path << std::endl;
|
||||
sendErrorResponse(400, true, "bad URL:" + path);
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
|
||||
void sendBody2()
|
||||
{
|
||||
stringstream d;
|
||||
@@ -337,32 +407,36 @@ public:
|
||||
push(d.str().c_str());
|
||||
bufferSend(body2, body2Size);
|
||||
}
|
||||
|
||||
|
||||
void sendErrorResponse(int code, bool close, string content)
|
||||
{
|
||||
cerr << "sending error " << code << " for " << path << endl;
|
||||
cerr << "\tcontent:" << content << endl;
|
||||
|
||||
stringstream headerData;
|
||||
headerData << "HTTP/1.1 " << code << " " << reasonForCode(code) << "\r\n";
|
||||
headerData << "Content-Length:" << content.size() << "\r\n";
|
||||
headerData << "\r\n"; // final CRLF to terminate the headers
|
||||
push(headerData.str().c_str());
|
||||
push(content.c_str());
|
||||
|
||||
|
||||
if (close) {
|
||||
closeWhenDone();
|
||||
}
|
||||
}
|
||||
|
||||
string reasonForCode(int code)
|
||||
|
||||
string reasonForCode(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case 200: return "OK";
|
||||
case 201: return "Created";
|
||||
case 204: return "no content";
|
||||
case 404: return "not found";
|
||||
case 407: return "proxy authentication required";
|
||||
default: return "unknown code";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
State state;
|
||||
string buffer;
|
||||
string method;
|
||||
@@ -376,7 +450,7 @@ public:
|
||||
class TestServer : public NetChannel
|
||||
{
|
||||
simgear::NetChannelPoller _poller;
|
||||
public:
|
||||
public:
|
||||
TestServer()
|
||||
{
|
||||
Socket::initSockets();
|
||||
@@ -384,14 +458,14 @@ public:
|
||||
open();
|
||||
bind(NULL, 2000); // localhost, any port
|
||||
listen(5);
|
||||
|
||||
|
||||
_poller.addChannel(this);
|
||||
}
|
||||
|
||||
|
||||
virtual ~TestServer()
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual bool writable (void) { return false ; }
|
||||
|
||||
virtual void handleAccept (void)
|
||||
@@ -401,10 +475,10 @@ public:
|
||||
//cout << "did accept from " << addr.getHost() << ":" << addr.getPort() << endl;
|
||||
TestServerChannel* chan = new TestServerChannel();
|
||||
chan->setHandle(handle);
|
||||
|
||||
|
||||
_poller.addChannel(chan);
|
||||
}
|
||||
|
||||
|
||||
void poll()
|
||||
{
|
||||
_poller.poll();
|
||||
@@ -419,13 +493,13 @@ void waitForComplete(HTTP::Client* cl, TestRequest* tr)
|
||||
while (start.elapsedMSec() < 10000) {
|
||||
cl->update();
|
||||
testServer.poll();
|
||||
|
||||
|
||||
if (tr->complete) {
|
||||
return;
|
||||
}
|
||||
SGTimeStamp::sleepForMSec(15);
|
||||
}
|
||||
|
||||
|
||||
cerr << "timed out" << endl;
|
||||
}
|
||||
|
||||
@@ -435,23 +509,24 @@ void waitForFailed(HTTP::Client* cl, TestRequest* tr)
|
||||
while (start.elapsedMSec() < 10000) {
|
||||
cl->update();
|
||||
testServer.poll();
|
||||
|
||||
|
||||
if (tr->failed) {
|
||||
return;
|
||||
}
|
||||
SGTimeStamp::sleepForMSec(15);
|
||||
}
|
||||
|
||||
|
||||
cerr << "timed out waiting for failure" << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
sglog().setLogLevels( SG_ALL, SG_INFO );
|
||||
|
||||
HTTP::Client cl;
|
||||
// force all requests to use the same connection for this test
|
||||
cl.setMaxConnections(1);
|
||||
|
||||
cl.setMaxConnections(1);
|
||||
|
||||
// test URL parsing
|
||||
TestRequest* tr1 = new TestRequest("http://localhost.woo.zar:2000/test1?foo=bar");
|
||||
COMPARE(tr1->scheme(), "http");
|
||||
@@ -459,14 +534,14 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr1->host(), "localhost.woo.zar");
|
||||
COMPARE(tr1->port(), 2000);
|
||||
COMPARE(tr1->path(), "/test1");
|
||||
|
||||
|
||||
TestRequest* tr2 = new TestRequest("http://192.168.1.1/test1/dir/thing/file.png");
|
||||
COMPARE(tr2->scheme(), "http");
|
||||
COMPARE(tr2->hostAndPort(), "192.168.1.1");
|
||||
COMPARE(tr2->host(), "192.168.1.1");
|
||||
COMPARE(tr2->port(), 80);
|
||||
COMPARE(tr2->path(), "/test1/dir/thing/file.png");
|
||||
|
||||
|
||||
// basic get request
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
|
||||
@@ -480,12 +555,12 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/testLorem");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
|
||||
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 200);
|
||||
COMPARE(tr->responseReason(), string("OK"));
|
||||
@@ -493,7 +568,7 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY3));
|
||||
COMPARE(tr->bodyData, string(BODY3));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -501,9 +576,7 @@ int main(int argc, char* argv[])
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 200);
|
||||
}
|
||||
|
||||
cerr << "done args" << endl;
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_headers");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -518,12 +591,12 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
// larger get request
|
||||
for (unsigned int i=0; i<body2Size; ++i) {
|
||||
body2[i] = (i << 4) | (i >> 2);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test2");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -533,8 +606,8 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), body2Size);
|
||||
COMPARE(tr->bodyData, string(body2, body2Size));
|
||||
}
|
||||
|
||||
cerr << "testing chunked" << endl;
|
||||
|
||||
cerr << "testing chunked transfer encoding" << endl;
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/testchunked");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -548,7 +621,7 @@ int main(int argc, char* argv[])
|
||||
// check trailers made it too
|
||||
COMPARE(tr->headers["x-foobar"], string("wibble"));
|
||||
}
|
||||
|
||||
|
||||
// test 404
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/not-found");
|
||||
@@ -595,15 +668,40 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
cout << "done3" << endl;
|
||||
// test connectToHost failure
|
||||
/*
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://not.found/something");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForFailed(tr);
|
||||
COMPARE(tr->responseCode(), -1);
|
||||
waitForFailed(&cl, tr);
|
||||
|
||||
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
const int HOST_NOT_FOUND_CODE = CURLE_COULDNT_RESOLVE_HOST;
|
||||
#else
|
||||
const int HOST_NOT_FOUND_CODE = ENOENT;
|
||||
#endif
|
||||
COMPARE(tr->responseCode(), HOST_NOT_FOUND_CODE);
|
||||
}
|
||||
*/
|
||||
|
||||
cout << "testing abrupt close" << endl;
|
||||
// test server-side abrupt close
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_abrupt_close");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForFailed(&cl, tr);
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
const int SERVER_NO_DATA_CODE = CURLE_GOT_NOTHING;
|
||||
#else
|
||||
const int SERVER_NO_DATA_CODE = 500;
|
||||
#endif
|
||||
COMPARE(tr->responseCode(), SERVER_NO_DATA_CODE);
|
||||
}
|
||||
|
||||
cout << "testing proxy close" << endl;
|
||||
// test proxy
|
||||
{
|
||||
cl.setProxy("localhost", 2000);
|
||||
@@ -615,9 +713,10 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseLength(), body2Size);
|
||||
COMPARE(tr->bodyData, string(body2, body2Size));
|
||||
}
|
||||
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
{
|
||||
cl.setProxy("localhost", 2000, "ABCDEF");
|
||||
cl.setProxy("localhost", 2000, "johndoe:swordfish");
|
||||
TestRequest* tr = new TestRequest("http://www.google.com/test3");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
@@ -626,81 +725,105 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), body2Size);
|
||||
COMPARE(tr->bodyData, string(body2, body2Size));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// pipelining
|
||||
cout << "testing HTTP 1.1 pipelineing" << endl;
|
||||
|
||||
cout << "testing HTTP 1.1 pipelining" << endl;
|
||||
|
||||
{
|
||||
|
||||
|
||||
cl.setProxy("", 80);
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
|
||||
|
||||
|
||||
|
||||
TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
|
||||
HTTP::Request_ptr own2(tr2);
|
||||
cl.makeRequest(tr2);
|
||||
|
||||
|
||||
TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
|
||||
HTTP::Request_ptr own3(tr3);
|
||||
cl.makeRequest(tr3);
|
||||
|
||||
|
||||
waitForComplete(&cl, tr3);
|
||||
VERIFY(tr->complete);
|
||||
VERIFY(tr2->complete);
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
|
||||
|
||||
COMPARE(tr2->responseLength(), strlen(BODY3));
|
||||
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
|
||||
COMPARE(tr2->bodyData, string(BODY3));
|
||||
|
||||
|
||||
COMPARE(tr3->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
// multiple requests with an HTTP 1.0 server
|
||||
{
|
||||
cout << "http 1.0 multiple requests" << endl;
|
||||
|
||||
|
||||
cl.setProxy("", 80);
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0/A");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
|
||||
|
||||
TestRequest* tr2 = new TestRequest("http://localhost:2000/test_1_0/B");
|
||||
HTTP::Request_ptr own2(tr2);
|
||||
cl.makeRequest(tr2);
|
||||
|
||||
|
||||
TestRequest* tr3 = new TestRequest("http://localhost:2000/test_1_0/C");
|
||||
HTTP::Request_ptr own3(tr3);
|
||||
cl.makeRequest(tr3);
|
||||
|
||||
|
||||
waitForComplete(&cl, tr3);
|
||||
VERIFY(tr->complete);
|
||||
VERIFY(tr2->complete);
|
||||
|
||||
|
||||
COMPARE(tr->responseLength(), strlen(BODY1));
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
|
||||
|
||||
COMPARE(tr2->responseLength(), strlen(BODY3));
|
||||
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
|
||||
COMPARE(tr2->bodyData, string(BODY3));
|
||||
COMPARE(tr3->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
// POST
|
||||
{
|
||||
cout << "POST" << endl;
|
||||
cout << "testing POST" << endl;
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_post?foo=abc&bar=1234&username=johndoe", "POST");
|
||||
tr->setBodyData("", "application/x-www-form-urlencoded");
|
||||
|
||||
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 204);
|
||||
}
|
||||
|
||||
|
||||
// PUT
|
||||
{
|
||||
cout << "testing PUT" << endl;
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_put", "PUT");
|
||||
tr->setBodyData(BODY3, "x-application/foobar");
|
||||
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 204);
|
||||
}
|
||||
|
||||
{
|
||||
cout << "testing PUT create" << endl;
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_create", "PUT");
|
||||
tr->setBodyData(BODY3, "x-application/foobar");
|
||||
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 201);
|
||||
}
|
||||
|
||||
// test_zero_length_content
|
||||
{
|
||||
cout << "zero-length-content-response" << endl;
|
||||
@@ -712,8 +835,8 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->bodyData, string());
|
||||
COMPARE(tr->responseBytesReceived(), 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cout << "all tests passed ok" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
// Put in some bullet-proofing to handle magnetic and geographic poles.
|
||||
// 3/28/2000 EAW
|
||||
//
|
||||
// Updated coefficient arrays to use the current WMM2005 model,
|
||||
// Updated coefficient arrays to use the current wmm2005 model,
|
||||
// (valid between 2005.0 and 2010.0)
|
||||
// Also removed unused variables and corrected earth radii constants
|
||||
// to the values for WGS84 and WMM2005.
|
||||
@@ -36,6 +36,20 @@
|
||||
//
|
||||
// 25/10/2006 Wim Van Hoydonck -- wim.van.hoydonck@gmail.com
|
||||
//
|
||||
//
|
||||
// Updated coefficient arrays to use the current WMM2015 model,
|
||||
// (valid between 2015.0 and 2020.0)
|
||||
// Also removed unused variables and corrected earth radii constants
|
||||
// to the values for WGS84 and WMM2015.
|
||||
// Reference:
|
||||
// A. Chulliat , S. Macmillan, P. Alken, C. Beggan, M.
|
||||
// Nair, B. Hamilton, A. Woods, V. Ridley,
|
||||
// S Maus, and A Thomson, December 2014, The
|
||||
// US/UK World Magnetic Model for 2015-2020,
|
||||
// NOAA Technical Report WMM2015_Report.pdf
|
||||
//
|
||||
// 18/06/2015 Jean-Paul Anceaux -- j.p.r.anceaux@gmail.com
|
||||
|
||||
|
||||
// The routine uses a spherical harmonic expansion of the magnetic
|
||||
// potential up to twelfth order, together with its time variation, as
|
||||
@@ -52,7 +66,7 @@
|
||||
// the magnetic poles (where it is ill-defined) where the error may reach
|
||||
// 4 degrees or more.
|
||||
//
|
||||
// Variation is undefined at both the geographic and
|
||||
// Variation is undefined at both the geographic and
|
||||
// magnetic poles, even though the field itself is well-behaved. To
|
||||
// avoid the routine blowing up, latitude entries corresponding to
|
||||
// the geographic poles are slightly offset. At the magnetic poles,
|
||||
@@ -90,72 +104,72 @@ static const double a = 6378.137; /* semi-major axis (equatorial radius) o
|
||||
static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
|
||||
static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
|
||||
|
||||
static double gnm_wmm2005[13][13] =
|
||||
static double gnm_wmm2015[13][13] =
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-29556.8, -1671.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2340.6, 3046.9, 1657.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{1335.4, -2305.1, 1246.7, 674.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{919.8, 798.1, 211.3, -379.4, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-227.4, 354.6, 208.7, -136.5, -168.3, -14.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{73.2, 69.7, 76.7, -151.2, -14.9, 14.6, -86.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{80.1, -74.5, -1.4, 38.5, 12.4, 9.5, 5.7, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{24.9, 7.7, -11.6, -6.9, -18.2, 10.0, 9.2, -11.6, -5.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{5.6, 9.9, 3.5, -7.0, 5.1, -10.8, -1.3, 8.8, -6.7, -9.1, 0.0, 0.0, 0.0},
|
||||
{-2.3, -6.3, 1.6, -2.6, 0.0, 3.1, 0.4, 2.1, 3.9, -0.1, -2.3, 0.0, 0.0},
|
||||
{2.8, -1.6, -1.7, 1.7, -0.1, 0.1, -0.7, 0.7, 1.8, 0.0, 1.1, 4.1, 0.0},
|
||||
{-2.4, -0.4, 0.2, 0.8, -0.3, 1.1, -0.5, 0.4, -0.3, -0.3, -0.1, -0.3, -0.1},
|
||||
{-29438.5, -1501.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2445.3, 3012.5, 1676.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{1351.1, -2352.3, 1225.6, 581.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{907.2, 813.7, 120.3, -335.0, 70.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-232.6, 360.1, 192.4, -141.0, -157.4, 4.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{69.5, 67.4, 72.8, -129.8, -29.0, 13.2, -70.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{81.6, -76.1, -6.8, 51.9, 15.0, 9.3, -2.8, 6.7, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{24.0, 8.6, -16.9, -3.2, -20.6, 13.3, 11.7, -16.0, -2.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{5.4, 8.8, 3.1, -3.1, 0.6, -13.3, -0.1, 8.7, -9.1, -10.5, 0.0, 0.0, 0.0},
|
||||
{-1.9, -6.5, 0.2, 0.6, -0.6, 1.7, -0.7, 2.1, 2.3, -1.8, -3.6, 0.0, 0.0},
|
||||
{3.1, -1.5, -2.3, 2.1, -0.9, 0.6, -0.7, 0.2, 1.7, -0.2, 0.4, 3.5, 0.0},
|
||||
{-2.0, -0.3, 0.4, 1.3, -0.9, 0.9, 0.1, 0.5, -0.4, -0.4, 0.2, -0.9, 0.0},
|
||||
};
|
||||
|
||||
static double hnm_wmm2005[13][13]=
|
||||
static double hnm_wmm2015[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 5079.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2594.7, -516.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -199.9, 269.3, -524.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 281.5, -226.0, 145.8, -304.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 42.4, 179.8, -123.0, -19.5, 103.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.3, 54.7, 63.6, -63.4, -0.1, 50.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -61.5, -22.4, 7.2, 25.4, 11.0, -26.4, -5.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 11.2, -21.0, 9.6, -19.8, 16.1, 7.7, -12.9, -0.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.1, 12.9, 12.6, -6.7, -8.1, 8.0, 2.9, -7.9, 6.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 2.4, 0.2, 4.4, 4.8, -6.5, -1.1, -3.4, -0.8, -2.3, -7.9, 0.0, 0.0},
|
||||
{0.0, 0.3, 1.2, -0.8, -2.5, 0.9, -0.6, -2.7, -0.9, -1.3, -2.0, -1.2, 0.0},
|
||||
{0.0, -0.4, 0.3, 2.4, -2.6, 0.6, 0.3, 0.0, 0.0, 0.3, -0.9, -0.4, 0.8},
|
||||
{0.0, 4796.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2845.6, -642.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -115.3, 245.0, -538.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 283.4, -188.6, 180.9, -329.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 47.4, 196.9, -119.4, 16.1, 100.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.7, 33.2, 58.8, -66.5, 7.3, 62.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -54.1, -19.4, 5.6, 24.4, 3.3, -27.5, -2.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 10.2, -18.1, 13.2, -14.6, 16.2, 5.7, -9.1, 2.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -21.6, 10.8, 11.7, -6.8, -6.9, 7.8, 1.0, -3.9, 8.5, 0.0, 0.0, 0.0},
|
||||
{0.0, 3.3, -0.3, 4.6, 4.4, -7.9, -0.6, -4.1, -2.8, -1.1, -8.7, 0.0, 0.0},
|
||||
{0.0, -0.1, 2.1, -0.7, -1.1, 0.7, -0.2, -2.1, -1.5, -2.5, -2.0, -2.3, 0.0},
|
||||
{0.0, -1.0, 0.5, 1.8, -2.2, 0.3, 0.7, -0.1, 0.3, 0.2, -0.9, -0.2, 0.7},
|
||||
};
|
||||
|
||||
static double gtnm_wmm2005[13][13]=
|
||||
static double gtnm_wmm2015[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{8.0, 10.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-15.1, -7.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.4, -2.6, -1.2, -6.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2.5, 2.8, -7.0, 6.2, -3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2.8, 0.7, -3.2, -1.1, 0.1, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.7, 0.4, -0.3, 2.3, -2.1, -0.6, 1.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.2, -0.1, -0.3, 1.1, 0.6, 0.5, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.1, 0.3, -0.4, 0.3, -0.3, 0.2, 0.4, -0.7, 0.4, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{10.7, 17.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-8.6, -3.3, 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{3.1, -6.2, -0.4, -10.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.4, 0.8, -9.2, 4.0, -4.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.2, 0.1, -1.4, 0.0, 1.3, 3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.5, -0.2, -0.6, 2.4, -1.1, 0.3, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.2, -0.2, -0.4, 1.3, 0.2, -0.4, -0.9, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.1, -0.5, 0.5, -0.2, 0.4, 0.2, -0.4, 0.3, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.1, -0.1, 0.4, -0.5, -0.2, 0.1, 0.0, -0.2, -0.1, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -0.1, 0.3, -0.1, -0.1, -0.1, 0.0, -0.2, -0.1, -0.2, 0.0, 0.0},
|
||||
{0.0, 0.0, -0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.1, -0.1, 0.0},
|
||||
{0.1, 0.0, 0.0, 0.1, -0.1, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
};
|
||||
|
||||
static double htnm_wmm2005[13][13]=
|
||||
static double htnm_wmm2015[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -23.2, -14.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 5.0, -7.0, -0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 2.2, 1.6, 5.8, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 1.7, 2.1, 4.8, -1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.6, -1.9, -0.4, -0.5, -0.3, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.6, 0.4, 0.2, 0.3, -0.8, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.2, 0.1, 0.3, 0.4, 0.1, -0.2, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -26.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -27.1, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 8.4, -0.4, 2.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.6, 5.3, 3.0, -5.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.4, 1.6, -1.1, 3.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -2.2, -0.7, 0.1, 1.0, 1.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.7, 0.5, -0.2, -0.1, -0.7, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.3, 0.3, 0.3, 0.6, -0.1, -0.2, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.2, -0.1, -0.2, 0.1, 0.1, 0.0, -0.2, 0.4, 0.3, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.1, -0.1, 0.0, 0.0, -0.2, 0.1, -0.1, -0.2, 0.1, -0.1, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.1, 0.0, 0.1, 0.0, 0.0, 0.1, 0.0, -0.1, 0.0, -0.1, 0.0},
|
||||
{0.0, 0.0, 0.0, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
};
|
||||
|
||||
static const int nmax = 12;
|
||||
@@ -174,7 +188,7 @@ static double roots[13][13][2];
|
||||
unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
|
||||
{
|
||||
unsigned long jd;
|
||||
|
||||
|
||||
yy = (yy < 50) ? (2000 + yy) : (1900 + yy);
|
||||
jd = dd - 32075L + 1461L * (yy + 4800L + (mm - 14) / 12 ) / 4;
|
||||
jd = jd + 367L * (mm - 2 - (mm - 14) / 12*12) / 12;
|
||||
@@ -182,7 +196,7 @@ unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
|
||||
|
||||
/* printf("julian date = %d\n", jd ); */
|
||||
return jd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -195,8 +209,8 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
{
|
||||
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||
int n,m;
|
||||
/* reference date for current model is 1 januari 2005 */
|
||||
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
|
||||
/* reference date for current model is 1 januari 2015 */
|
||||
long date0_wmm2015 = yymmdd_to_julian_days(15,1,1);
|
||||
|
||||
double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z;
|
||||
double sinpsi, cospsi, inv_s;
|
||||
@@ -215,7 +229,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
/* theta is geocentric co-latitude */
|
||||
|
||||
r = h*h + 2.0*h * sr +
|
||||
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
|
||||
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
|
||||
(a*a - (a*a - b*b) * sinlat*sinlat );
|
||||
|
||||
r = sqrt(r);
|
||||
@@ -224,7 +238,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
c = cos(theta);
|
||||
s = sin(theta);
|
||||
/* protect against zero divide at geographic poles */
|
||||
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
|
||||
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
|
||||
|
||||
/* zero out arrays */
|
||||
for ( n = 0; n <= nmax; n++ ) {
|
||||
@@ -283,12 +297,12 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
|
||||
/* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
|
||||
achieved by adjusting the coefficients at time t0 for linear secular variation */
|
||||
/* WMM2005 */
|
||||
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||
/* WMM2015 */
|
||||
yearfrac = (dat - date0_wmm2015) / 365.25;
|
||||
for ( n = 1; n <= nmax; n++ ) {
|
||||
for ( m = 0; m <= nmax; m++ ) {
|
||||
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
|
||||
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
|
||||
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +324,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
double c2_n=0;
|
||||
double c3_n=0;
|
||||
for ( m = 0; m <= n; m++ ) {
|
||||
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
|
||||
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
|
||||
c1_n=c1_n + tmp * P[n][m];
|
||||
c2_n=c2_n + tmp * DP[n][m];
|
||||
c3_n=c3_n + m * (gnm[n][m] * sm[m] - hnm[n][m] * cm[m]) * P[n][m];
|
||||
@@ -340,7 +354,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
/* find variation in radians */
|
||||
/* return zero variation at magnetic pole X=Y=0. */
|
||||
/* E is positive */
|
||||
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
|
||||
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +364,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||
int n,m;
|
||||
/* reference dates */
|
||||
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
|
||||
long date0_wmm2015 = yymmdd_to_julian_days(5,1,1);
|
||||
|
||||
double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z;
|
||||
|
||||
@@ -362,7 +376,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
/* theta is geocentric co-latitude */
|
||||
|
||||
r = h * h + 2.0*h * sr +
|
||||
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
|
||||
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
|
||||
(a * a - (a * a - b * b) * pow(sin(lat),2.0));
|
||||
|
||||
r = sqrt(r);
|
||||
@@ -407,12 +421,12 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
}
|
||||
|
||||
/* compute gnm, hnm at dat */
|
||||
/* WMM2005 */
|
||||
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||
/* WMM2015 */
|
||||
yearfrac = (dat - date0_wmm2015) / 365.25;
|
||||
for ( n = 1; n <= nmax; n++ ) {
|
||||
for ( m = 0; m <= nmax; m++ ) {
|
||||
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
|
||||
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
|
||||
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
static bool isNaN(const T& v)
|
||||
{
|
||||
#ifdef HAVE_ISNAN
|
||||
return isnan(v);
|
||||
return (isnan(v) != 0);
|
||||
#elif defined HAVE_STD_ISNAN
|
||||
return std::isnan(v);
|
||||
#else
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace simgear
|
||||
}
|
||||
|
||||
void setMaxSubdiv( size_t aMaxSubdiv ) { mMaxSubdiv = aMaxSubdiv; }
|
||||
void getMaxSubdiv() const { return mMaxSubdiv; }
|
||||
size_t getMaxSubdiv() const { return mMaxSubdiv; }
|
||||
PointList &pointList() { return mPointList; }
|
||||
const PointList &pointList() const { return mPointList; }
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ SGInterpTable::SGInterpTable( const std::string& file )
|
||||
while ( in ) {
|
||||
double ind, dep;
|
||||
in >> ind >> dep;
|
||||
in >> skipws;
|
||||
in >> std::skipws;
|
||||
_table[ind] = dep;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,25 +835,39 @@ SGPath SGPath::documents(const SGPath& def)
|
||||
//------------------------------------------------------------------------------
|
||||
std::string SGPath::realpath() const
|
||||
{
|
||||
#if (defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1050)
|
||||
// Workaround for Mac OS 10.5. Somehow fgfs crashes on Mac at ::realpath.
|
||||
// This means relative paths cannot be used on Mac OS <= 10.5
|
||||
return path;
|
||||
#else
|
||||
#if defined(_MSC_VER) /*for MS compilers */ || defined(_WIN32) /*needed for non MS windows compilers like MingW*/
|
||||
#if defined(_MSC_VER) /*for MS compilers */ || defined(_WIN32) /*needed for non MS windows compilers like MingW*/
|
||||
// with absPath NULL, will allocate, and ignore length
|
||||
char *buf = _fullpath( NULL, path.c_str(), _MAX_PATH );
|
||||
#else
|
||||
#else
|
||||
// POSIX
|
||||
char* buf = ::realpath(path.c_str(), NULL);
|
||||
#endif
|
||||
if (!buf)
|
||||
#endif
|
||||
if (!buf) // File does not exist: return the realpath it would have if created now
|
||||
// (needed for fgValidatePath security)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_ALERT, "ERROR: The path '" << path << "' does not exist in the file system.");
|
||||
return path;
|
||||
if (path.empty()) {
|
||||
return SGPath(".").realpath(); // current directory
|
||||
}
|
||||
std::string this_dir = dir();
|
||||
if (isAbsolute() && this_dir.empty()) { // top level
|
||||
this_dir = "/";
|
||||
}
|
||||
if (file() == "..") {
|
||||
this_dir = SGPath(SGPath(this_dir).realpath()).dir();
|
||||
if (this_dir.empty()) { // invalid path: .. above root
|
||||
return "";
|
||||
}
|
||||
return SGPath(this_dir).realpath(); // use native path separator,
|
||||
// and handle 'existing/nonexisting/../symlink' paths
|
||||
}
|
||||
return SGPath(this_dir).realpath() +
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
"\\" + file();
|
||||
#else
|
||||
"/" + file();
|
||||
#endif
|
||||
}
|
||||
std::string p(buf);
|
||||
free(buf);
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ std::string redirectUrlForVersion(const std::string& aVersion, SGPropertyNode_pt
|
||||
return v->getStringValue("url");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -77,8 +77,7 @@ public:
|
||||
m_owner(aOwner)
|
||||
{
|
||||
// refreshing
|
||||
m_owner->changeStatus(Delegate::FAIL_IN_PROGRESS);
|
||||
|
||||
m_owner->changeStatus(Delegate::STATUS_IN_PROGRESS);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -90,8 +89,13 @@ protected:
|
||||
virtual void onDone()
|
||||
{
|
||||
if (responseCode() != 200) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
|
||||
m_owner->refreshComplete(Delegate::FAIL_DOWNLOAD);
|
||||
Delegate::StatusCode code = Delegate::FAIL_DOWNLOAD;
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url()
|
||||
<< "\n\t" << responseCode());
|
||||
if (responseCode() == 404) {
|
||||
code = Delegate::FAIL_NOT_FOUND;
|
||||
}
|
||||
m_owner->refreshComplete(code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -106,7 +110,15 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
std::string ver(m_owner->root()->catalogVersion());
|
||||
if (m_owner->root()->catalogVersion() != props->getIntValue("catalog-version")) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "catalog:" << m_owner->url() << " is not version "
|
||||
<< m_owner->root()->catalogVersion());
|
||||
m_owner->refreshComplete(Delegate::FAIL_VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::string ver(m_owner->root()->applicationVersion());
|
||||
if (!checkVersion(ver, props)) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "downloaded catalog " << m_owner->url() << ", version mismatch:\n\t"
|
||||
<< props->getStringValue("version") << " vs required " << ver);
|
||||
@@ -138,7 +150,7 @@ protected:
|
||||
|
||||
time(&m_owner->m_retrievedTime);
|
||||
m_owner->writeTimestamp();
|
||||
m_owner->refreshComplete(Delegate::CATALOG_REFRESHED);
|
||||
m_owner->refreshComplete(Delegate::STATUS_REFRESHED);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -164,9 +176,7 @@ CatalogRef Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
|
||||
{
|
||||
CatalogRef c = new Catalog(aRoot);
|
||||
c->m_url = aUrl;
|
||||
Downloader* dl = new Downloader(c, aUrl);
|
||||
aRoot->makeHTTPRequest(dl);
|
||||
|
||||
c->refresh();
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -186,8 +196,8 @@ CatalogRef Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!checkVersion(aRoot->catalogVersion(), props)) {
|
||||
std::string redirect = redirectUrlForVersion(aRoot->catalogVersion(), props);
|
||||
if (!checkVersion(aRoot->applicationVersion(), props)) {
|
||||
std::string redirect = redirectUrlForVersion(aRoot->applicationVersion(), props);
|
||||
if (!redirect.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "catalog at " << aPath << ", version mismatch:\n\t"
|
||||
<< "redirecting to alternate URL:" << redirect);
|
||||
@@ -200,13 +210,18 @@ CatalogRef Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "creating catalog from:" << aPath);
|
||||
}
|
||||
|
||||
CatalogRef c = new Catalog(aRoot);
|
||||
c->m_installRoot = aPath;
|
||||
c->parseProps(props); // will set status
|
||||
c->parseProps(props);
|
||||
c->parseTimestamp();
|
||||
|
||||
// parsed XML ok, mark status as valid
|
||||
c->changeStatus(Delegate::STATUS_SUCCESS);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -214,7 +229,7 @@ bool Catalog::uninstall()
|
||||
{
|
||||
bool ok;
|
||||
bool atLeastOneFailure = false;
|
||||
|
||||
|
||||
BOOST_FOREACH(PackageRef p, installedPackages()) {
|
||||
ok = p->existingInstall()->uninstall();
|
||||
if (!ok) {
|
||||
@@ -231,9 +246,9 @@ bool Catalog::uninstall()
|
||||
if (!ok) {
|
||||
atLeastOneFailure = true;
|
||||
}
|
||||
|
||||
|
||||
changeStatus(atLeastOneFailure ? Delegate::FAIL_FILESYSTEM
|
||||
: Delegate::FAIL_SUCCESS);
|
||||
: Delegate::STATUS_SUCCESS);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -283,31 +298,31 @@ Catalog::installedPackages() const
|
||||
return r;
|
||||
}
|
||||
|
||||
InstallRef Catalog::installForPackage(PackageRef pkg) const
|
||||
{
|
||||
PackageInstallDict::const_iterator it = m_installed.find(pkg);
|
||||
if (it == m_installed.end()) {
|
||||
// check if it exists on disk, create
|
||||
|
||||
SGPath p(pkg->pathOnDisk());
|
||||
if (p.exists()) {
|
||||
return Install::createFromPath(p, CatalogRef(const_cast<Catalog*>(this)));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void Catalog::refresh()
|
||||
{
|
||||
if (m_refreshRequest.valid()) {
|
||||
// refresh in progress
|
||||
return;
|
||||
}
|
||||
|
||||
Downloader* dl = new Downloader(this, url());
|
||||
// will iupdate status to IN_PROGRESS
|
||||
m_refreshRequest = dl;
|
||||
// will update status to IN_PROGRESS
|
||||
m_root->makeHTTPRequest(dl);
|
||||
m_root->catalogRefreshBegin(this);
|
||||
}
|
||||
|
||||
struct FindById
|
||||
{
|
||||
FindById(const std::string &id) : m_id(id) {}
|
||||
|
||||
bool operator()(const PackageRef& ref) const
|
||||
{
|
||||
return ref->id() == m_id;
|
||||
}
|
||||
|
||||
std::string m_id;
|
||||
};
|
||||
|
||||
void Catalog::parseProps(const SGPropertyNode* aProps)
|
||||
{
|
||||
// copy everything except package children?
|
||||
@@ -321,8 +336,14 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
|
||||
for (int i = 0; i < nChildren; i++) {
|
||||
const SGPropertyNode* pkgProps = aProps->getChild(i);
|
||||
if (strcmp(pkgProps->getName(), "package") == 0) {
|
||||
PackageRef p = getPackageById(pkgProps->getStringValue("id"));
|
||||
if (p) {
|
||||
// can't use getPackageById here becuase the variant dict isn't
|
||||
// built yet. Instead we need to look at m_packages directly.
|
||||
|
||||
PackageList::iterator pit = std::find_if(m_packages.begin(), m_packages.end(),
|
||||
FindById(pkgProps->getStringValue("id")));
|
||||
PackageRef p;
|
||||
if (pit != m_packages.end()) {
|
||||
p = *pit;
|
||||
// existing package
|
||||
p->updateFromProps(pkgProps);
|
||||
orphans.erase(p); // not an orphan
|
||||
@@ -372,9 +393,6 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
|
||||
Dir d(m_installRoot);
|
||||
d.create(0755);
|
||||
}
|
||||
|
||||
// parsed XML ok, mark status as valid
|
||||
changeStatus(Delegate::FAIL_SUCCESS);
|
||||
}
|
||||
|
||||
PackageRef Catalog::getPackageById(const std::string& aId) const
|
||||
@@ -383,11 +401,23 @@ PackageRef Catalog::getPackageById(const std::string& aId) const
|
||||
// works as expected.
|
||||
PackageWeakMap::const_iterator it = m_variantDict.find(aId);
|
||||
if (it == m_variantDict.end())
|
||||
return NULL;
|
||||
return PackageRef();
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
PackageRef Catalog::getPackageByPath(const std::string& aPath) const
|
||||
{
|
||||
PackageList::const_iterator it;
|
||||
for (it = m_packages.begin(); it != m_packages.end(); ++it) {
|
||||
if ((*it)->dirName() == aPath) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return PackageRef();
|
||||
}
|
||||
|
||||
std::string Catalog::id() const
|
||||
{
|
||||
return m_props->getStringValue("id");
|
||||
@@ -398,6 +428,11 @@ std::string Catalog::url() const
|
||||
return m_url;
|
||||
}
|
||||
|
||||
std::string Catalog::name() const
|
||||
{
|
||||
return getLocalisedString(m_props, "name");
|
||||
}
|
||||
|
||||
std::string Catalog::description() const
|
||||
{
|
||||
return getLocalisedString(m_props, "description");
|
||||
@@ -440,6 +475,10 @@ bool Catalog::needsRefresh() const
|
||||
|
||||
std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
|
||||
{
|
||||
if (!aRoot) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (aRoot->hasChild(m_root->getLocale())) {
|
||||
const SGPropertyNode* localeRoot = aRoot->getChild(m_root->getLocale().c_str());
|
||||
if (localeRoot->hasChild(aName)) {
|
||||
@@ -450,37 +489,20 @@ std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char*
|
||||
return aRoot->getStringValue(aName);
|
||||
}
|
||||
|
||||
void Catalog::refreshComplete(Delegate::FailureCode aReason)
|
||||
void Catalog::refreshComplete(Delegate::StatusCode aReason)
|
||||
{
|
||||
m_root->catalogRefreshComplete(this, aReason);
|
||||
changeStatus(aReason);
|
||||
m_refreshRequest.reset();
|
||||
}
|
||||
|
||||
void Catalog::registerInstall(Install* ins)
|
||||
{
|
||||
if (!ins || ins->package()->catalog() != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_installed[ins->package()] = ins;
|
||||
}
|
||||
|
||||
void Catalog::unregisterInstall(Install* ins)
|
||||
{
|
||||
if (!ins || ins->package()->catalog() != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_installed.erase(ins->package());
|
||||
}
|
||||
|
||||
void Catalog::changeStatus(Delegate::FailureCode newStatus)
|
||||
void Catalog::changeStatus(Delegate::StatusCode newStatus)
|
||||
{
|
||||
if (m_status == newStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_status = newStatus;
|
||||
m_root->catalogRefreshStatus(this, newStatus);
|
||||
m_statusCallbacks(this);
|
||||
}
|
||||
|
||||
@@ -489,7 +511,7 @@ void Catalog::addStatusCallback(const Callback& cb)
|
||||
m_statusCallbacks.push_back(cb);
|
||||
}
|
||||
|
||||
Delegate::FailureCode Catalog::status() const
|
||||
Delegate::StatusCode Catalog::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/structure/function_list.hxx>
|
||||
#include <simgear/io/HTTPRequest.hxx>
|
||||
|
||||
#include <simgear/package/Delegate.hxx>
|
||||
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
* uninstall this catalog entirely, including all installed packages
|
||||
*/
|
||||
bool uninstall();
|
||||
|
||||
|
||||
/**
|
||||
* perform a refresh of the catalog contents
|
||||
*/
|
||||
@@ -105,11 +106,13 @@ public:
|
||||
|
||||
std::string url() const;
|
||||
|
||||
std::string name() const;
|
||||
|
||||
std::string description() const;
|
||||
|
||||
PackageRef getPackageById(const std::string& aId) const;
|
||||
|
||||
InstallRef installForPackage(PackageRef pkg) const;
|
||||
PackageRef getPackageByPath(const std::string& aPath) const;
|
||||
|
||||
/**
|
||||
* test if the catalog data was retrieved longer ago than the
|
||||
@@ -123,11 +126,11 @@ public:
|
||||
* access the raw property data in the catalog
|
||||
*/
|
||||
SGPropertyNode* properties() const;
|
||||
|
||||
Delegate::FailureCode status() const;
|
||||
|
||||
|
||||
Delegate::StatusCode status() const;
|
||||
|
||||
typedef boost::function<void(Catalog*)> Callback;
|
||||
|
||||
|
||||
void addStatusCallback(const Callback& cb);
|
||||
|
||||
template<class C>
|
||||
@@ -141,38 +144,30 @@ private:
|
||||
class Downloader;
|
||||
friend class Downloader;
|
||||
|
||||
friend class Install;
|
||||
void registerInstall(Install* ins);
|
||||
void unregisterInstall(Install* ins);
|
||||
|
||||
void parseProps(const SGPropertyNode* aProps);
|
||||
|
||||
void refreshComplete(Delegate::FailureCode aReason);
|
||||
void refreshComplete(Delegate::StatusCode aReason);
|
||||
|
||||
void parseTimestamp();
|
||||
void writeTimestamp();
|
||||
|
||||
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
|
||||
|
||||
void changeStatus(Delegate::FailureCode newStatus);
|
||||
void changeStatus(Delegate::StatusCode newStatus);
|
||||
|
||||
Root* m_root;
|
||||
SGPropertyNode_ptr m_props;
|
||||
SGPath m_installRoot;
|
||||
std::string m_url;
|
||||
Delegate::FailureCode m_status;
|
||||
|
||||
Delegate::StatusCode m_status;
|
||||
HTTP::Request_ptr m_refreshRequest;
|
||||
|
||||
PackageList m_packages;
|
||||
time_t m_retrievedTime;
|
||||
|
||||
typedef std::map<std::string, Package*> PackageWeakMap;
|
||||
PackageWeakMap m_variantDict;
|
||||
|
||||
// important that this is a weak-ref to Installs,
|
||||
// since it is only cleaned up in the Install destructor
|
||||
typedef std::map<PackageRef, Install*> PackageInstallDict;
|
||||
PackageInstallDict m_installed;
|
||||
|
||||
function_list<Callback> m_statusCallbacks;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,15 +18,21 @@
|
||||
#ifndef SG_PACKAGE_DELEGATE_HXX
|
||||
#define SG_PACKAGE_DELEGATE_HXX
|
||||
|
||||
#include <simgear/misc/stdint.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
|
||||
namespace pkg
|
||||
{
|
||||
|
||||
|
||||
class Install;
|
||||
class Catalog;
|
||||
|
||||
|
||||
typedef SGSharedPtr<Catalog> CatalogRef;
|
||||
typedef SGSharedPtr<Install> InstallRef;
|
||||
|
||||
/**
|
||||
* package delegate is the mechanism to discover progress / completion /
|
||||
* errors in packaging steps asynchronously.
|
||||
@@ -35,41 +41,42 @@ class Delegate
|
||||
{
|
||||
public:
|
||||
typedef enum {
|
||||
FAIL_SUCCESS = 0, ///< not a failure :)
|
||||
STATUS_SUCCESS = 0,
|
||||
FAIL_UNKNOWN = 1,
|
||||
FAIL_IN_PROGRESS, ///< downloading/installation in progress (not a failure :P)
|
||||
FAIL_CHECKSUM, ///< package MD5 verificstion failed
|
||||
FAIL_DOWNLOAD, ///< network issue
|
||||
FAIL_EXTRACT, ///< package archive failed to extract cleanly
|
||||
STATUS_IN_PROGRESS, ///< downloading/installation in progress
|
||||
FAIL_CHECKSUM, ///< package MD5 verificstion failed
|
||||
FAIL_DOWNLOAD, ///< network issue
|
||||
FAIL_EXTRACT, ///< package archive failed to extract cleanly
|
||||
FAIL_FILESYSTEM, ///< unknown filesystem error occurred
|
||||
FAIL_VERSION, ///< version check mismatch
|
||||
CATALOG_REFRESHED
|
||||
} FailureCode;
|
||||
|
||||
|
||||
FAIL_VERSION, ///< version check mismatch
|
||||
FAIL_NOT_FOUND, ///< package URL returned a 404
|
||||
STATUS_REFRESHED,
|
||||
USER_CANCELLED
|
||||
} StatusCode;
|
||||
|
||||
|
||||
virtual ~Delegate() { }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* invoked when all catalogs have finished refreshing - either successfully
|
||||
* or with a failure.
|
||||
* emitted when a catalog refesh completes, either success or failure
|
||||
* If catalog is null, this means /all/ catalogs have been refreshed
|
||||
*/
|
||||
virtual void refreshComplete() = 0;
|
||||
|
||||
virtual void catalogRefreshed(CatalogRef, StatusCode aReason) = 0;
|
||||
|
||||
virtual void startInstall(InstallRef aInstall) = 0;
|
||||
virtual void installProgress(InstallRef aInstall, unsigned int aBytes, unsigned int aTotal) = 0;
|
||||
virtual void finishInstall(InstallRef aInstall, StatusCode aReason) = 0;
|
||||
|
||||
/**
|
||||
* emitted when a catalog fails to refresh, due to a network issue or
|
||||
* some other failure.
|
||||
* Notification when catalogs/packages are added or removed
|
||||
*/
|
||||
virtual void failedRefresh(Catalog*, FailureCode aReason) = 0;
|
||||
|
||||
virtual void startInstall(Install* aInstall) = 0;
|
||||
virtual void installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal) = 0;
|
||||
virtual void finishInstall(Install* aInstall) = 0;
|
||||
|
||||
|
||||
virtual void failedInstall(Install* aInstall, FailureCode aReason) = 0;
|
||||
|
||||
};
|
||||
|
||||
virtual void availablePackagesChanged() {}
|
||||
|
||||
virtual void dataForThumbnail(const std::string& aThumbnailUrl,
|
||||
size_t lenth, const uint8_t* bytes) {}
|
||||
};
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <simgear/package/md5.h>
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/package/Catalog.hxx>
|
||||
#include <simgear/package/Package.hxx>
|
||||
#include <simgear/package/Root.hxx>
|
||||
@@ -37,7 +38,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
namespace simgear {
|
||||
|
||||
|
||||
namespace pkg {
|
||||
|
||||
class Install::PackageArchiveDownloader : public HTTP::Request
|
||||
@@ -45,48 +46,87 @@ class Install::PackageArchiveDownloader : public HTTP::Request
|
||||
public:
|
||||
PackageArchiveDownloader(InstallRef aOwner) :
|
||||
HTTP::Request("" /* dummy URL */),
|
||||
m_owner(aOwner)
|
||||
m_owner(aOwner),
|
||||
m_downloaded(0)
|
||||
{
|
||||
m_urls = m_owner->package()->downloadUrls();
|
||||
if (m_urls.empty()) {
|
||||
throw sg_exception("no package download URLs");
|
||||
}
|
||||
|
||||
|
||||
// TODO randomise order of m_urls
|
||||
|
||||
|
||||
m_extractPath = aOwner->path().dir();
|
||||
m_extractPath.append("_DOWNLOAD"); // add some temporary value
|
||||
|
||||
m_extractPath.append("_extract_" + aOwner->package()->md5());
|
||||
|
||||
// clean up any existing files
|
||||
Dir d(m_extractPath);
|
||||
if (d.exists()) {
|
||||
d.remove(true /* recursive */);
|
||||
}
|
||||
}
|
||||
|
||||
~PackageArchiveDownloader()
|
||||
{
|
||||
// always clean up our extraction dir: if we successfully downloaded
|
||||
// and installed it will be an empty dir, if we failed it might contain
|
||||
// (some) of the package files.
|
||||
Dir d(m_extractPath);
|
||||
if (d.exists()) {
|
||||
d.remove(true /* recursive */);
|
||||
}
|
||||
}
|
||||
|
||||
size_t downloadedBytes() const
|
||||
{
|
||||
return m_downloaded;
|
||||
}
|
||||
|
||||
int percentDownloaded() const
|
||||
{
|
||||
if (responseLength() <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (m_downloaded * 100) / responseLength();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::string url() const
|
||||
{
|
||||
return m_urls.front();
|
||||
}
|
||||
|
||||
|
||||
virtual void responseHeadersComplete()
|
||||
{
|
||||
Request::responseHeadersComplete();
|
||||
|
||||
Dir d(m_extractPath);
|
||||
d.create(0755);
|
||||
|
||||
d.create(0755);
|
||||
|
||||
memset(&m_md5, 0, sizeof(SG_MD5_CTX));
|
||||
SG_MD5Init(&m_md5);
|
||||
}
|
||||
|
||||
|
||||
virtual void gotBodyData(const char* s, int n)
|
||||
{
|
||||
m_buffer += std::string(s, n);
|
||||
SG_MD5Update(&m_md5, (unsigned char*) s, n);
|
||||
|
||||
|
||||
m_downloaded = m_buffer.size();
|
||||
m_owner->installProgress(m_buffer.size(), responseLength());
|
||||
}
|
||||
|
||||
|
||||
virtual void onDone()
|
||||
{
|
||||
if (responseCode() != 200) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "download failure");
|
||||
doFailure(Delegate::FAIL_DOWNLOAD);
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "download failure:" << responseCode() <<
|
||||
"\n\t" << url());
|
||||
Delegate::StatusCode code = Delegate::FAIL_DOWNLOAD;
|
||||
if (responseCode() == 404) {
|
||||
code = Delegate::FAIL_NOT_FOUND;
|
||||
}
|
||||
|
||||
doFailure(code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,65 +143,79 @@ protected:
|
||||
doFailure(Delegate::FAIL_CHECKSUM);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!extractUnzip()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "zip extraction failed");
|
||||
doFailure(Delegate::FAIL_EXTRACT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_owner->path().exists()) {
|
||||
//std::cout << "removing existing path" << std::endl;
|
||||
Dir destDir(m_owner->path());
|
||||
destDir.remove(true /* recursive */);
|
||||
}
|
||||
|
||||
m_extractPath.append(m_owner->package()->id());
|
||||
bool ok = m_extractPath.rename(m_owner->path());
|
||||
|
||||
// build a path like /path/to/packages/org.some.catalog/Aircraft/extract_xxxx/MyAircraftDir
|
||||
SGPath extractedPath = m_extractPath;
|
||||
extractedPath.append(m_owner->package()->dirName());
|
||||
|
||||
// rename it to path/to/packages/org.some.catalog/Aircraft/MyAircraftDir
|
||||
bool ok = extractedPath.rename(m_owner->path());
|
||||
if (!ok) {
|
||||
doFailure(Delegate::FAIL_FILESYSTEM);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_owner->m_revision = m_owner->package()->revision();
|
||||
m_owner->writeRevisionFile();
|
||||
m_owner->installResult(Delegate::FAIL_SUCCESS);
|
||||
m_owner->m_download.reset(); // so isDownloading reports false
|
||||
|
||||
m_owner->installResult(Delegate::STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
virtual void onFail()
|
||||
{
|
||||
if (responseCode() == -1) {
|
||||
doFailure(Delegate::USER_CANCELLED);
|
||||
} else {
|
||||
doFailure(Delegate::FAIL_DOWNLOAD);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
|
||||
{
|
||||
unz_file_info fileInfo;
|
||||
unzGetCurrentFileInfo(zip, &fileInfo,
|
||||
buffer, bufferSize,
|
||||
unzGetCurrentFileInfo(zip, &fileInfo,
|
||||
buffer, bufferSize,
|
||||
NULL, 0, /* extra field */
|
||||
NULL, 0 /* comment field */);
|
||||
|
||||
|
||||
std::string name(buffer);
|
||||
// no absolute paths, no 'up' traversals
|
||||
// we could also look for suspicious file extensions here (forbid .dll, .exe, .so)
|
||||
if ((name[0] == '/') || (name.find("../") != std::string::npos) || (name.find("..\\") != std::string::npos)) {
|
||||
throw sg_format_exception("Bad zip path", name);
|
||||
}
|
||||
|
||||
|
||||
if (fileInfo.uncompressed_size == 0) {
|
||||
// assume it's a directory for now
|
||||
// since we create parent directories when extracting
|
||||
// a path, we're done here
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int result = unzOpenCurrentFile(zip);
|
||||
if (result != UNZ_OK) {
|
||||
throw sg_io_exception("opening current zip file failed", sg_location(name));
|
||||
}
|
||||
|
||||
|
||||
std::ofstream outFile;
|
||||
bool eof = false;
|
||||
SGPath path(m_extractPath);
|
||||
path.append(name);
|
||||
|
||||
|
||||
// create enclosing directory heirarchy as required
|
||||
Dir parentDir(path.dir());
|
||||
if (!parentDir.exists()) {
|
||||
@@ -170,12 +224,12 @@ private:
|
||||
throw sg_io_exception("failed to create directory heirarchy for extraction", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
outFile.open(path.c_str(), std::ios::binary | std::ios::trunc | std::ios::out);
|
||||
if (outFile.fail()) {
|
||||
throw sg_io_exception("failed to open output file for writing", path.c_str());
|
||||
}
|
||||
|
||||
|
||||
while (!eof) {
|
||||
int bytes = unzReadCurrentFile(zip, buffer, bufferSize);
|
||||
if (bytes < 0) {
|
||||
@@ -186,30 +240,30 @@ private:
|
||||
outFile.write(buffer, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
outFile.close();
|
||||
unzCloseCurrentFile(zip);
|
||||
}
|
||||
|
||||
|
||||
bool extractUnzip()
|
||||
{
|
||||
bool result = true;
|
||||
zlib_filefunc_def memoryAccessFuncs;
|
||||
fill_memory_filefunc(&memoryAccessFuncs);
|
||||
|
||||
|
||||
char bufferName[128];
|
||||
snprintf(bufferName, 128, "%p+%lx", m_buffer.data(), m_buffer.size());
|
||||
unzFile zip = unzOpen2(bufferName, &memoryAccessFuncs);
|
||||
|
||||
|
||||
const size_t BUFFER_SIZE = 32 * 1024;
|
||||
void* buf = malloc(BUFFER_SIZE);
|
||||
|
||||
|
||||
try {
|
||||
int result = unzGoToFirstFile(zip);
|
||||
if (result != UNZ_OK) {
|
||||
throw sg_exception("failed to go to first file in archive");
|
||||
}
|
||||
|
||||
|
||||
while (true) {
|
||||
extractCurrentFile(zip, (char*) buf, BUFFER_SIZE);
|
||||
result = unzGoToNextFile(zip);
|
||||
@@ -222,57 +276,53 @@ private:
|
||||
} catch (sg_exception& e) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
|
||||
free(buf);
|
||||
unzClose(zip);
|
||||
return result;
|
||||
}
|
||||
|
||||
void doFailure(Delegate::FailureCode aReason)
|
||||
|
||||
void doFailure(Delegate::StatusCode aReason)
|
||||
{
|
||||
Dir dir(m_extractPath);
|
||||
dir.remove(true /* recursive */);
|
||||
|
||||
if (m_urls.size() == 1) {
|
||||
std::cout << "failure:" << aReason << std::endl;
|
||||
m_owner->installResult(aReason);
|
||||
return;
|
||||
if (dir.exists()) {
|
||||
dir.remove(true /* recursive */);
|
||||
}
|
||||
|
||||
std::cout << "retrying download" << std::endl;
|
||||
m_urls.erase(m_urls.begin()); // pop first URL
|
||||
|
||||
// TODO - try other mirrors
|
||||
m_owner->m_download.reset(); // ensure we get cleaned up
|
||||
m_owner->installResult(aReason);
|
||||
}
|
||||
|
||||
|
||||
InstallRef m_owner;
|
||||
string_list m_urls;
|
||||
SG_MD5_CTX m_md5;
|
||||
std::string m_buffer;
|
||||
SGPath m_extractPath;
|
||||
size_t m_downloaded;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Install::Install(PackageRef aPkg, const SGPath& aPath) :
|
||||
m_package(aPkg),
|
||||
m_path(aPath),
|
||||
m_download(NULL),
|
||||
_status(Delegate::FAIL_IN_PROGRESS)
|
||||
m_status(Delegate::STATUS_IN_PROGRESS)
|
||||
{
|
||||
parseRevision();
|
||||
m_package->catalog()->registerInstall(this);
|
||||
m_package->catalog()->root()->registerInstall(this);
|
||||
}
|
||||
|
||||
|
||||
Install::~Install()
|
||||
{
|
||||
m_package->catalog()->unregisterInstall(this);
|
||||
}
|
||||
|
||||
InstallRef Install::createFromPath(const SGPath& aPath, CatalogRef aCat)
|
||||
{
|
||||
std::string id = aPath.file();
|
||||
PackageRef pkg = aCat->getPackageById(id);
|
||||
std::string path = aPath.file();
|
||||
PackageRef pkg = aCat->getPackageByPath(path);
|
||||
if (!pkg)
|
||||
throw sg_exception("no package with id:" + id);
|
||||
|
||||
throw sg_exception("no package with path:" + path);
|
||||
|
||||
return new Install(pkg, aPath);
|
||||
}
|
||||
|
||||
@@ -284,7 +334,7 @@ void Install::parseRevision()
|
||||
m_revision = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::ifstream f(revisionFile.c_str(), std::ios::in);
|
||||
f >> m_revision;
|
||||
}
|
||||
@@ -307,7 +357,7 @@ void Install::startUpdate()
|
||||
if (m_download) {
|
||||
return; // already active
|
||||
}
|
||||
|
||||
|
||||
m_download = new PackageArchiveDownloader(this);
|
||||
m_package->catalog()->root()->makeHTTPRequest(m_download);
|
||||
m_package->catalog()->root()->startInstall(this);
|
||||
@@ -320,20 +370,95 @@ bool Install::uninstall()
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "package uninstall failed: couldn't remove path " << m_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_package->catalog()->unregisterInstall(this);
|
||||
|
||||
m_package->catalog()->root()->unregisterInstall(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Install::isDownloading() const
|
||||
{
|
||||
return (m_download != NULL);
|
||||
return (m_download.valid());
|
||||
}
|
||||
|
||||
bool Install::isQueued() const
|
||||
{
|
||||
return m_package->catalog()->root()->isInstallQueued(const_cast<Install*>(this));
|
||||
}
|
||||
|
||||
int Install::downloadedPercent() const
|
||||
{
|
||||
if (!m_download.valid()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PackageArchiveDownloader* dl = static_cast<PackageArchiveDownloader*>(m_download.get());
|
||||
return dl->percentDownloaded();
|
||||
}
|
||||
|
||||
size_t Install::downloadedBytes() const
|
||||
{
|
||||
if (!m_download.valid()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PackageArchiveDownloader* dl = static_cast<PackageArchiveDownloader*>(m_download.get());
|
||||
return dl->downloadedBytes();
|
||||
|
||||
}
|
||||
|
||||
void Install::cancelDownload()
|
||||
{
|
||||
if (m_download.valid()) {
|
||||
m_download->abort("User cancelled download");
|
||||
}
|
||||
|
||||
if (m_revision == 0) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "cancel install of package, will unregister");
|
||||
m_package->catalog()->root()->unregisterInstall(this);
|
||||
}
|
||||
|
||||
m_package->catalog()->root()->cancelDownload(this);
|
||||
}
|
||||
|
||||
struct PathAppender
|
||||
{
|
||||
PathAppender(const SGPath& p) : m_path(p) {}
|
||||
|
||||
SGPath operator()(const std::string& s) const
|
||||
{
|
||||
SGPath p(m_path);
|
||||
p.append(s);
|
||||
return p;
|
||||
}
|
||||
|
||||
SGPath m_path;
|
||||
};
|
||||
|
||||
PathList Install::thumbnailPaths() const
|
||||
{
|
||||
const string_list& thumbs(m_package->thumbnails());
|
||||
PathList result;
|
||||
if (thumbs.empty())
|
||||
return result;
|
||||
|
||||
std::transform(thumbs.begin(), thumbs.end(),
|
||||
std::back_inserter(result),
|
||||
PathAppender(m_path));
|
||||
return result;
|
||||
}
|
||||
|
||||
SGPath Install::primarySetPath() const
|
||||
{
|
||||
SGPath setPath(m_path);
|
||||
std::string ps(m_package->id());
|
||||
setPath.append(ps + "-set.xml");
|
||||
return setPath;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Install* Install::done(const Callback& cb)
|
||||
{
|
||||
if( _status == Delegate::FAIL_SUCCESS )
|
||||
if( m_status == Delegate::STATUS_SUCCESS )
|
||||
cb(this);
|
||||
else
|
||||
_cb_done.push_back(cb);
|
||||
@@ -344,8 +469,8 @@ Install* Install::done(const Callback& cb)
|
||||
//------------------------------------------------------------------------------
|
||||
Install* Install::fail(const Callback& cb)
|
||||
{
|
||||
if( _status != Delegate::FAIL_SUCCESS
|
||||
&& _status != Delegate::FAIL_IN_PROGRESS )
|
||||
if( m_status != Delegate::STATUS_SUCCESS
|
||||
&& m_status != Delegate::STATUS_IN_PROGRESS )
|
||||
cb(this);
|
||||
else
|
||||
_cb_fail.push_back(cb);
|
||||
@@ -356,7 +481,7 @@ Install* Install::fail(const Callback& cb)
|
||||
//------------------------------------------------------------------------------
|
||||
Install* Install::always(const Callback& cb)
|
||||
{
|
||||
if( _status != Delegate::FAIL_IN_PROGRESS )
|
||||
if( m_status != Delegate::STATUS_IN_PROGRESS )
|
||||
cb(this);
|
||||
else
|
||||
_cb_always.push_back(cb);
|
||||
@@ -372,13 +497,12 @@ Install* Install::progress(const ProgressCallback& cb)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Install::installResult(Delegate::FailureCode aReason)
|
||||
void Install::installResult(Delegate::StatusCode aReason)
|
||||
{
|
||||
if (aReason == Delegate::FAIL_SUCCESS) {
|
||||
m_package->catalog()->root()->finishInstall(this);
|
||||
m_package->catalog()->root()->finishInstall(this, aReason);
|
||||
if (aReason == Delegate::STATUS_SUCCESS) {
|
||||
_cb_done(this);
|
||||
} else {
|
||||
m_package->catalog()->root()->failedInstall(this, aReason);
|
||||
_cb_fail(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
#include <vector>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
#include <simgear/package/Delegate.hxx>
|
||||
|
||||
#include <simgear/structure/function_list.hxx>
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/io/HTTPRequest.hxx>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
@@ -78,6 +80,31 @@ public:
|
||||
|
||||
bool isDownloading() const;
|
||||
|
||||
bool isQueued() const;
|
||||
|
||||
int downloadedPercent() const;
|
||||
|
||||
size_t downloadedBytes() const;
|
||||
|
||||
/**
|
||||
* full path to the primary -set.xml file for this install
|
||||
*/
|
||||
SGPath primarySetPath() const;
|
||||
|
||||
/**
|
||||
* if a download is in progress, cancel it. If this is the first install
|
||||
* of the package (as opposed to an update), the install will be cleaned
|
||||
* up once the last reference is gone.
|
||||
*/
|
||||
void cancelDownload();
|
||||
|
||||
/**
|
||||
* return the thumbnails associated with this install, but as locations
|
||||
* on the file system, not URLs. It is assumed the order of thumbnails
|
||||
* is consistent with the URLs returned from Package::thumbnailUrls()
|
||||
*/
|
||||
PathList thumbnailPaths() const;
|
||||
|
||||
/**
|
||||
* Set the handler to be called when the installation successfully
|
||||
* completes.
|
||||
@@ -147,16 +174,16 @@ private:
|
||||
void parseRevision();
|
||||
void writeRevisionFile();
|
||||
|
||||
void installResult(Delegate::FailureCode aReason);
|
||||
void installResult(Delegate::StatusCode aReason);
|
||||
void installProgress(unsigned int aBytes, unsigned int aTotal);
|
||||
|
||||
PackageRef m_package;
|
||||
unsigned int m_revision; ///< revision on disk
|
||||
SGPath m_path; ///< installation point on disk
|
||||
|
||||
PackageArchiveDownloader* m_download;
|
||||
HTTP::Request_ptr m_download;
|
||||
|
||||
Delegate::FailureCode _status;
|
||||
Delegate::StatusCode m_status;
|
||||
|
||||
function_list<Callback> _cb_done,
|
||||
_cb_fail,
|
||||
|
||||
@@ -117,7 +117,7 @@ SGPath Package::pathOnDisk() const
|
||||
{
|
||||
SGPath p(m_catalog->installRoot());
|
||||
p.append("Aircraft");
|
||||
p.append(id());
|
||||
p.append(dirName());
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,12 @@ InstallRef Package::install()
|
||||
|
||||
InstallRef Package::existingInstall(const InstallCallback& cb) const
|
||||
{
|
||||
InstallRef install = m_catalog->installForPackage(const_cast<Package*>(this));
|
||||
InstallRef install;
|
||||
try {
|
||||
install = m_catalog->root()->existingInstallForPackage(const_cast<Package*>(this));
|
||||
} catch (std::exception& e) {
|
||||
return InstallRef();
|
||||
}
|
||||
|
||||
if( cb )
|
||||
{
|
||||
@@ -162,13 +167,30 @@ std::string Package::qualifiedId() const
|
||||
return m_catalog->id() + "." + id();
|
||||
}
|
||||
|
||||
std::string Package::qualifiedVariantId(const unsigned int variantIndex) const
|
||||
{
|
||||
return m_catalog->id() + "." + variants()[variantIndex];
|
||||
}
|
||||
|
||||
std::string Package::md5() const
|
||||
{
|
||||
return m_props->getStringValue("md5");
|
||||
}
|
||||
|
||||
std::string Package::dirName() const
|
||||
{
|
||||
std::string r(m_props->getStringValue("dir"));
|
||||
if (r.empty())
|
||||
throw sg_exception("missing dir property on catalog package entry for " + m_id);
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned int Package::revision() const
|
||||
{
|
||||
if (!m_props) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_props->getIntValue("revision");
|
||||
}
|
||||
|
||||
@@ -200,15 +222,36 @@ SGPropertyNode* Package::properties() const
|
||||
string_list Package::thumbnailUrls() const
|
||||
{
|
||||
string_list r;
|
||||
if (!m_props) {
|
||||
return r;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail")) {
|
||||
r.push_back(dl->getStringValue());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
string_list Package::thumbnails() const
|
||||
{
|
||||
string_list r;
|
||||
if (!m_props) {
|
||||
return r;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail-path")) {
|
||||
r.push_back(dl->getStringValue());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
string_list Package::downloadUrls() const
|
||||
{
|
||||
string_list r;
|
||||
if (!m_props) {
|
||||
return r;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("url")) {
|
||||
r.push_back(dl->getStringValue());
|
||||
}
|
||||
@@ -295,6 +338,20 @@ std::string Package::nameForVariant(const std::string& vid) const
|
||||
throw sg_exception("Unknow variant +" + vid + " in package " + id());
|
||||
}
|
||||
|
||||
std::string Package::nameForVariant(const unsigned int vIndex) const
|
||||
{
|
||||
if (vIndex == 0)
|
||||
return name();
|
||||
|
||||
// offset by minus one to allow for index 0 being the primary
|
||||
SGPropertyNode_ptr var = m_props->getChild("variant", vIndex - 1);
|
||||
if (var)
|
||||
return var->getStringValue("name");
|
||||
|
||||
throw sg_exception("Unknow variant in package " + id());
|
||||
}
|
||||
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
@@ -75,6 +75,11 @@ public:
|
||||
* Fully-qualified ID, including our catalog'd ID
|
||||
*/
|
||||
std::string qualifiedId() const;
|
||||
|
||||
/**
|
||||
* Fully-qualified ID, including our catalog'd ID
|
||||
*/
|
||||
std::string qualifiedVariantId(const unsigned int variantIndex) const;
|
||||
|
||||
/**
|
||||
* human-readable name - note this is probably not localised,
|
||||
@@ -87,6 +92,8 @@ public:
|
||||
*/
|
||||
std::string nameForVariant(const std::string& vid) const;
|
||||
|
||||
std::string nameForVariant(const unsigned int vIndex) const;
|
||||
|
||||
/**
|
||||
* syntactic sugar to get the localised description
|
||||
*/
|
||||
@@ -122,16 +129,28 @@ public:
|
||||
|
||||
string_list thumbnailUrls() const;
|
||||
|
||||
/**
|
||||
* thumbnail file paths within the package on disk
|
||||
*/
|
||||
string_list thumbnails() const;
|
||||
|
||||
/**
|
||||
* Packages we depend upon.
|
||||
* If the dependency list cannot be satisifed for some reason,
|
||||
* this will raise an sg_exception.
|
||||
*/
|
||||
PackageList dependencies() const;
|
||||
|
||||
/**
|
||||
* Name of the package directory on disk. This may or may not be the
|
||||
* same as the primary ID, depending on the aircraft author
|
||||
*/
|
||||
std::string dirName() const;
|
||||
private:
|
||||
SGPath pathOnDisk() const;
|
||||
|
||||
friend class Catalog;
|
||||
friend class Root;
|
||||
|
||||
Package(const SGPropertyNode* aProps, CatalogRef aCatalog);
|
||||
|
||||
|
||||
@@ -34,45 +34,172 @@
|
||||
#include <simgear/package/Catalog.hxx>
|
||||
|
||||
namespace simgear {
|
||||
|
||||
|
||||
namespace pkg {
|
||||
|
||||
typedef std::map<std::string, CatalogRef> CatalogDict;
|
||||
|
||||
typedef std::vector<Delegate*> DelegateVec;
|
||||
typedef std::map<std::string, std::string> MemThumbnailCache;
|
||||
typedef std::deque<std::string> StringDeque;
|
||||
|
||||
class Root::ThumbnailDownloader : public HTTP::Request
|
||||
{
|
||||
public:
|
||||
ThumbnailDownloader(Root::RootPrivate* aOwner, const std::string& aUrl) :
|
||||
HTTP::Request(aUrl),
|
||||
m_owner(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void gotBodyData(const char* s, int n)
|
||||
{
|
||||
m_buffer += std::string(s, n);
|
||||
}
|
||||
|
||||
virtual void onDone();
|
||||
|
||||
private:
|
||||
Root::RootPrivate* m_owner;
|
||||
std::string m_buffer;
|
||||
};
|
||||
|
||||
class Root::RootPrivate
|
||||
{
|
||||
public:
|
||||
RootPrivate() :
|
||||
http(NULL),
|
||||
maxAgeSeconds(60 * 60 * 24),
|
||||
delegate(NULL)
|
||||
maxAgeSeconds(60 * 60 * 24)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void fireStartInstall(InstallRef install)
|
||||
{
|
||||
DelegateVec::const_iterator it;
|
||||
for (it = delegates.begin(); it != delegates.end(); ++it) {
|
||||
(*it)->startInstall(install);
|
||||
}
|
||||
}
|
||||
|
||||
void fireInstallProgress(InstallRef install,
|
||||
unsigned int aBytes, unsigned int aTotal)
|
||||
{
|
||||
DelegateVec::const_iterator it;
|
||||
for (it = delegates.begin(); it != delegates.end(); ++it) {
|
||||
(*it)->installProgress(install, aBytes, aTotal);
|
||||
}
|
||||
}
|
||||
|
||||
void fireFinishInstall(InstallRef install, Delegate::StatusCode status)
|
||||
{
|
||||
DelegateVec::const_iterator it;
|
||||
for (it = delegates.begin(); it != delegates.end(); ++it) {
|
||||
(*it)->finishInstall(install, status);
|
||||
}
|
||||
}
|
||||
|
||||
void fireRefreshStatus(CatalogRef catalog, Delegate::StatusCode status)
|
||||
{
|
||||
DelegateVec::const_iterator it;
|
||||
for (it = delegates.begin(); it != delegates.end(); ++it) {
|
||||
(*it)->catalogRefreshed(catalog, status);
|
||||
}
|
||||
}
|
||||
|
||||
void firePackagesChanged()
|
||||
{
|
||||
DelegateVec::const_iterator it;
|
||||
for (it = delegates.begin(); it != delegates.end(); ++it) {
|
||||
(*it)->availablePackagesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void thumbnailDownloadComplete(HTTP::Request_ptr request,
|
||||
Delegate::StatusCode status, const std::string& bytes)
|
||||
{
|
||||
std::string u(request->url());
|
||||
if (status == Delegate::STATUS_SUCCESS) {
|
||||
thumbnailCache[u] = bytes;
|
||||
fireDataForThumbnail(u, bytes);
|
||||
}
|
||||
|
||||
downloadNextPendingThumbnail();
|
||||
}
|
||||
|
||||
void fireDataForThumbnail(const std::string& aUrl, const std::string& bytes)
|
||||
{
|
||||
DelegateVec::const_iterator it;
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(bytes.data());
|
||||
for (it = delegates.begin(); it != delegates.end(); ++it) {
|
||||
(*it)->dataForThumbnail(aUrl, bytes.size(), data);
|
||||
}
|
||||
}
|
||||
|
||||
void downloadNextPendingThumbnail()
|
||||
{
|
||||
thumbnailDownloadRequest.clear();
|
||||
if (pendingThumbnails.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string u = pendingThumbnails.front();
|
||||
pendingThumbnails.pop_front();
|
||||
thumbnailDownloadRequest = new Root::ThumbnailDownloader(this, u);
|
||||
|
||||
if (http) {
|
||||
http->makeRequest(thumbnailDownloadRequest);
|
||||
} else {
|
||||
httpPendingRequests.push_back(thumbnailDownloadRequest);
|
||||
}
|
||||
}
|
||||
|
||||
DelegateVec delegates;
|
||||
|
||||
SGPath path;
|
||||
std::string locale;
|
||||
HTTP::Client* http;
|
||||
CatalogDict catalogs;
|
||||
unsigned int maxAgeSeconds;
|
||||
Delegate* delegate;
|
||||
std::string version;
|
||||
|
||||
|
||||
std::set<CatalogRef> refreshing;
|
||||
std::deque<InstallRef> updateDeque;
|
||||
typedef std::deque<InstallRef> UpdateDeque;
|
||||
UpdateDeque updateDeque;
|
||||
std::deque<HTTP::Request_ptr> httpPendingRequests;
|
||||
|
||||
HTTP::Request_ptr thumbnailDownloadRequest;
|
||||
StringDeque pendingThumbnails;
|
||||
MemThumbnailCache thumbnailCache;
|
||||
|
||||
typedef std::map<PackageRef, InstallRef> InstallCache;
|
||||
InstallCache m_installs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void Root::ThumbnailDownloader::onDone()
|
||||
{
|
||||
if (responseCode() != 200) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "thumbnail download failure:" << url());
|
||||
m_owner->thumbnailDownloadComplete(this, Delegate::FAIL_DOWNLOAD, std::string());
|
||||
return;
|
||||
}
|
||||
|
||||
m_owner->thumbnailDownloadComplete(this, Delegate::STATUS_SUCCESS, m_buffer);
|
||||
//time(&m_owner->m_retrievedTime);
|
||||
//m_owner->writeTimestamp();
|
||||
//m_owner->refreshComplete(Delegate::STATUS_REFRESHED);
|
||||
}
|
||||
|
||||
SGPath Root::path() const
|
||||
{
|
||||
return d->path;
|
||||
}
|
||||
|
||||
|
||||
void Root::setMaxAgeSeconds(unsigned int seconds)
|
||||
{
|
||||
d->maxAgeSeconds = seconds;
|
||||
}
|
||||
|
||||
|
||||
unsigned int Root::maxAgeSeconds() const
|
||||
{
|
||||
return d->maxAgeSeconds;
|
||||
@@ -94,10 +221,10 @@ void Root::makeHTTPRequest(HTTP::Request *req)
|
||||
d->http->makeRequest(req);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
d->httpPendingRequests.push_back(req);
|
||||
}
|
||||
|
||||
|
||||
Root::Root(const SGPath& aPath, const std::string& aVersion) :
|
||||
d(new RootPrivate)
|
||||
{
|
||||
@@ -106,13 +233,13 @@ Root::Root(const SGPath& aPath, const std::string& aVersion) :
|
||||
if (getenv("LOCALE")) {
|
||||
d->locale = getenv("LOCALE");
|
||||
}
|
||||
|
||||
|
||||
Dir dir(aPath);
|
||||
if (!dir.exists()) {
|
||||
dir.create(0755);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BOOST_FOREACH(SGPath c, dir.children(Dir::TYPE_DIR)) {
|
||||
CatalogRef cat = Catalog::createFromPath(this, c);
|
||||
if (cat) {
|
||||
@@ -123,28 +250,33 @@ Root::Root(const SGPath& aPath, const std::string& aVersion) :
|
||||
|
||||
Root::~Root()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::string Root::catalogVersion() const
|
||||
|
||||
int Root::catalogVersion() const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
std::string Root::applicationVersion() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
|
||||
CatalogRef Root::getCatalogById(const std::string& aId) const
|
||||
{
|
||||
CatalogDict::const_iterator it = d->catalogs.find(aId);
|
||||
if (it == d->catalogs.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
PackageRef Root::getPackageById(const std::string& aName) const
|
||||
{
|
||||
size_t lastDot = aName.rfind('.');
|
||||
|
||||
|
||||
PackageRef pkg = NULL;
|
||||
if (lastDot == std::string::npos) {
|
||||
// naked package ID
|
||||
@@ -155,17 +287,17 @@ PackageRef Root::getPackageById(const std::string& aName) const
|
||||
return pkg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
std::string catalogId = aName.substr(0, lastDot);
|
||||
std::string id = aName.substr(lastDot + 1);
|
||||
std::string id = aName.substr(lastDot + 1);
|
||||
CatalogRef catalog = getCatalogById(catalogId);
|
||||
if (!catalog) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
return catalog->getPackageById(id);
|
||||
}
|
||||
|
||||
@@ -176,7 +308,21 @@ CatalogList Root::catalogs() const
|
||||
for (; it != d->catalogs.end(); ++it) {
|
||||
r.push_back(it->second);
|
||||
}
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
PackageList
|
||||
Root::allPackages() const
|
||||
{
|
||||
PackageList r;
|
||||
|
||||
CatalogDict::const_iterator it = d->catalogs.begin();
|
||||
for (; it != d->catalogs.end(); ++it) {
|
||||
const PackageList& r2(it->second->packages());
|
||||
r.insert(r.end(), r2.begin(), r2.end());
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -184,13 +330,13 @@ PackageList
|
||||
Root::packagesMatching(const SGPropertyNode* aFilter) const
|
||||
{
|
||||
PackageList r;
|
||||
|
||||
|
||||
CatalogDict::const_iterator it = d->catalogs.begin();
|
||||
for (; it != d->catalogs.end(); ++it) {
|
||||
PackageList r2(it->second->packagesMatching(aFilter));
|
||||
r.insert(r.end(), r2.begin(), r2.end());
|
||||
}
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -198,31 +344,48 @@ PackageList
|
||||
Root::packagesNeedingUpdate() const
|
||||
{
|
||||
PackageList r;
|
||||
|
||||
|
||||
CatalogDict::const_iterator it = d->catalogs.begin();
|
||||
for (; it != d->catalogs.end(); ++it) {
|
||||
PackageList r2(it->second->packagesNeedingUpdate());
|
||||
r.insert(r.end(), r2.begin(), r2.end());
|
||||
}
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void Root::refresh(bool aForce)
|
||||
{
|
||||
bool didStartAny = false;
|
||||
CatalogDict::iterator it = d->catalogs.begin();
|
||||
for (; it != d->catalogs.end(); ++it) {
|
||||
if (aForce || it->second->needsRefresh()) {
|
||||
it->second->refresh();
|
||||
didStartAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!didStartAny) {
|
||||
// signal refresh complete to the delegate already
|
||||
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
|
||||
}
|
||||
}
|
||||
|
||||
void Root::setDelegate(simgear::pkg::Delegate *aDelegate)
|
||||
void Root::addDelegate(simgear::pkg::Delegate *aDelegate)
|
||||
{
|
||||
d->delegate = aDelegate;
|
||||
d->delegates.push_back(aDelegate);
|
||||
}
|
||||
|
||||
|
||||
void Root::removeDelegate(simgear::pkg::Delegate *aDelegate)
|
||||
{
|
||||
DelegateVec::iterator it = std::find(d->delegates.begin(),
|
||||
d->delegates.end(), aDelegate);
|
||||
if (it == d->delegates.end()) {
|
||||
throw sg_exception("unknown delegate in removeDelegate");
|
||||
}
|
||||
d->delegates.erase(it);
|
||||
}
|
||||
|
||||
void Root::setLocale(const std::string& aLocale)
|
||||
{
|
||||
d->locale = aLocale;
|
||||
@@ -238,7 +401,7 @@ void Root::scheduleToUpdate(InstallRef aInstall)
|
||||
if (!aInstall) {
|
||||
throw sg_exception("missing argument to scheduleToUpdate");
|
||||
}
|
||||
|
||||
|
||||
PackageList deps = aInstall->package()->dependencies();
|
||||
BOOST_FOREACH(Package* dep, deps) {
|
||||
// will internally schedule for update if required
|
||||
@@ -248,24 +411,27 @@ void Root::scheduleToUpdate(InstallRef aInstall)
|
||||
|
||||
bool wasEmpty = d->updateDeque.empty();
|
||||
d->updateDeque.push_back(aInstall);
|
||||
|
||||
|
||||
if (wasEmpty) {
|
||||
aInstall->startUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
bool Root::isInstallQueued(InstallRef aInstall) const
|
||||
{
|
||||
RootPrivate::UpdateDeque::const_iterator it =
|
||||
std::find(d->updateDeque.begin(), d->updateDeque.end(), aInstall);
|
||||
return (it != d->updateDeque.end());
|
||||
}
|
||||
|
||||
void Root::startInstall(InstallRef aInstall)
|
||||
{
|
||||
if (d->delegate) {
|
||||
d->delegate->startInstall(aInstall.ptr());
|
||||
}
|
||||
d->fireStartInstall(aInstall);
|
||||
}
|
||||
|
||||
void Root::installProgress(InstallRef aInstall, unsigned int aBytes, unsigned int aTotal)
|
||||
{
|
||||
if (d->delegate) {
|
||||
d->delegate->installProgress(aInstall.ptr(), aBytes, aTotal);
|
||||
}
|
||||
d->fireInstallProgress(aInstall, aBytes, aTotal);
|
||||
}
|
||||
|
||||
void Root::startNext(InstallRef aCurrent)
|
||||
@@ -275,45 +441,52 @@ void Root::startNext(InstallRef aCurrent)
|
||||
} else {
|
||||
d->updateDeque.pop_front();
|
||||
}
|
||||
|
||||
|
||||
if (!d->updateDeque.empty()) {
|
||||
d->updateDeque.front()->startUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void Root::finishInstall(InstallRef aInstall)
|
||||
void Root::finishInstall(InstallRef aInstall, Delegate::StatusCode aReason)
|
||||
{
|
||||
if (d->delegate) {
|
||||
d->delegate->finishInstall(aInstall.ptr());
|
||||
if (aReason != Delegate::STATUS_SUCCESS) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "failed to install package:"
|
||||
<< aInstall->package()->id() << ":" << aReason);
|
||||
}
|
||||
|
||||
|
||||
// order matters here, so a call to 'isQueued' from a finish-install
|
||||
// callback returns false, not true
|
||||
startNext(aInstall);
|
||||
d->fireFinishInstall(aInstall, aReason);
|
||||
}
|
||||
|
||||
void Root::failedInstall(InstallRef aInstall, Delegate::FailureCode aReason)
|
||||
void Root::cancelDownload(InstallRef aInstall)
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "failed to install package:"
|
||||
<< aInstall->package()->id() << ":" << aReason);
|
||||
if (d->delegate) {
|
||||
d->delegate->failedInstall(aInstall.ptr(), aReason);
|
||||
}
|
||||
|
||||
startNext(aInstall);
|
||||
RootPrivate::UpdateDeque::iterator it =
|
||||
std::find(d->updateDeque.begin(), d->updateDeque.end(), aInstall);
|
||||
if (it != d->updateDeque.end()) {
|
||||
bool startNext = (aInstall == d->updateDeque.front());
|
||||
d->updateDeque.erase(it);
|
||||
if (startNext) {
|
||||
if (!d->updateDeque.empty()) {
|
||||
d->updateDeque.front()->startUpdate();
|
||||
}
|
||||
} // of install was front item
|
||||
} // of found install in queue
|
||||
}
|
||||
|
||||
void Root::catalogRefreshBegin(CatalogRef aCat)
|
||||
{
|
||||
d->refreshing.insert(aCat);
|
||||
}
|
||||
|
||||
void Root::catalogRefreshComplete(CatalogRef aCat, Delegate::FailureCode aReason)
|
||||
void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
|
||||
{
|
||||
CatalogDict::iterator catIt = d->catalogs.find(aCat->id());
|
||||
if (aReason != Delegate::FAIL_SUCCESS) {
|
||||
if (d->delegate) {
|
||||
d->delegate->failedRefresh(aCat, aReason);
|
||||
}
|
||||
|
||||
d->fireRefreshStatus(aCat, aReason);
|
||||
|
||||
if (aReason == Delegate::STATUS_IN_PROGRESS) {
|
||||
d->refreshing.insert(aCat);
|
||||
} else {
|
||||
d->refreshing.erase(aCat);
|
||||
}
|
||||
|
||||
if ((aReason != Delegate::STATUS_REFRESHED) && (aReason != Delegate::STATUS_IN_PROGRESS)) {
|
||||
// if the failure is permanent, delete the catalog from our
|
||||
// list (don't touch it on disk)
|
||||
bool isPermanentFailure = (aReason == Delegate::FAIL_VERSION);
|
||||
@@ -323,16 +496,16 @@ void Root::catalogRefreshComplete(CatalogRef aCat, Delegate::FailureCode aReason
|
||||
d->catalogs.erase(catIt);
|
||||
}
|
||||
}
|
||||
} else if (catIt == d->catalogs.end()) {
|
||||
// first fresh, add to our storage now
|
||||
}
|
||||
|
||||
if ((aReason == Delegate::STATUS_REFRESHED) && (catIt == d->catalogs.end())) {
|
||||
assert(!aCat->id().empty());
|
||||
d->catalogs.insert(catIt, CatalogDict::value_type(aCat->id(), aCat));
|
||||
}
|
||||
|
||||
d->refreshing.erase(aCat);
|
||||
|
||||
if (d->refreshing.empty()) {
|
||||
if (d->delegate) {
|
||||
d->delegate->refreshComplete();
|
||||
}
|
||||
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
|
||||
d->firePackagesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,21 +516,79 @@ bool Root::removeCatalogById(const std::string& aId)
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: unknown ID:" << aId);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CatalogRef cat = catIt->second;
|
||||
|
||||
|
||||
// drop the reference
|
||||
d->catalogs.erase(catIt);
|
||||
|
||||
|
||||
bool ok = cat->uninstall();
|
||||
if (!ok) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: catalog :" << aId
|
||||
<< "failed to uninstall");
|
||||
}
|
||||
|
||||
|
||||
// notify that a catalog is being removed
|
||||
d->firePackagesChanged();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void Root::requestThumbnailData(const std::string& aUrl)
|
||||
{
|
||||
MemThumbnailCache::iterator it = d->thumbnailCache.find(aUrl);
|
||||
if (it == d->thumbnailCache.end()) {
|
||||
// insert into cache to mark as pending
|
||||
d->pendingThumbnails.push_front(aUrl);
|
||||
d->thumbnailCache[aUrl] = std::string();
|
||||
d->downloadNextPendingThumbnail();
|
||||
} else if (!it->second.empty()) {
|
||||
// already loaded, fire data synchronously
|
||||
d->fireDataForThumbnail(aUrl, it->second);
|
||||
} else {
|
||||
// in cache but empty data, still fetching
|
||||
}
|
||||
}
|
||||
|
||||
InstallRef Root::existingInstallForPackage(PackageRef p) const
|
||||
{
|
||||
RootPrivate::InstallCache::const_iterator it =
|
||||
d->m_installs.find(p);
|
||||
if (it == d->m_installs.end()) {
|
||||
// check if it exists on disk, create
|
||||
SGPath path(p->pathOnDisk());
|
||||
if (path.exists()) {
|
||||
// this will add to our cache, and hence, modify m_installs
|
||||
return Install::createFromPath(path, p->catalog());
|
||||
}
|
||||
|
||||
// insert a null reference into the dictionary, so we don't call
|
||||
// the pathOnDisk -> exists codepath repeatedley
|
||||
d->m_installs[p] = InstallRef();
|
||||
return InstallRef();
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void Root::registerInstall(InstallRef ins)
|
||||
{
|
||||
if (!ins.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->m_installs[ins->package()] = ins;
|
||||
}
|
||||
|
||||
void Root::unregisterInstall(InstallRef ins)
|
||||
{
|
||||
if (!ins .valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->m_installs.erase(ins->package());
|
||||
}
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
@@ -62,8 +62,10 @@ public:
|
||||
|
||||
void setLocale(const std::string& aLocale);
|
||||
|
||||
void setDelegate(Delegate* aDelegate);
|
||||
|
||||
void addDelegate(Delegate* aDelegate);
|
||||
|
||||
void removeDelegate(Delegate* aDelegate);
|
||||
|
||||
std::string getLocale() const;
|
||||
|
||||
CatalogList catalogs() const;
|
||||
@@ -81,17 +83,28 @@ public:
|
||||
void makeHTTPRequest(HTTP::Request* req);
|
||||
|
||||
/**
|
||||
* the version string of the root. Catalogs must match this version,
|
||||
* The catalog XML/property version in use. This is used to make incomaptible
|
||||
* changes to the package/catalog syntax
|
||||
*/
|
||||
int catalogVersion() const;
|
||||
|
||||
/**
|
||||
* the version string of the application. Catalogs must match this version,
|
||||
* or they will be ignored / rejected.
|
||||
*/
|
||||
std::string catalogVersion() const;
|
||||
|
||||
std::string applicationVersion() const;
|
||||
|
||||
/**
|
||||
* refresh catalogs which are more than the maximum age (24 hours by default)
|
||||
* set force to true, to download all catalogs regardless of age.
|
||||
*/
|
||||
void refresh(bool aForce = false);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PackageList allPackages() const;
|
||||
|
||||
/**
|
||||
* retrieve packages matching a filter.
|
||||
* filter consists of required / minimum values, AND-ed together.
|
||||
@@ -115,21 +128,33 @@ public:
|
||||
* from the catalog too.
|
||||
*/
|
||||
bool removeCatalogById(const std::string& aId);
|
||||
|
||||
/**
|
||||
* request thumbnail data from the cache / network
|
||||
*/
|
||||
void requestThumbnailData(const std::string& aUrl);
|
||||
|
||||
bool isInstallQueued(InstallRef aInstall) const;
|
||||
private:
|
||||
friend class Install;
|
||||
friend class Catalog;
|
||||
friend class Package;
|
||||
|
||||
|
||||
void catalogRefreshBegin(CatalogRef aCat);
|
||||
void catalogRefreshComplete(CatalogRef aCat, Delegate::FailureCode aReason);
|
||||
InstallRef existingInstallForPackage(PackageRef p) const;
|
||||
|
||||
void catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason);
|
||||
|
||||
void startNext(InstallRef aCurrent);
|
||||
|
||||
void startInstall(InstallRef aInstall);
|
||||
void installProgress(InstallRef aInstall, unsigned int aBytes, unsigned int aTotal);
|
||||
void finishInstall(InstallRef aInstall);
|
||||
void failedInstall(InstallRef aInstall, Delegate::FailureCode aReason);
|
||||
|
||||
void finishInstall(InstallRef aInstall, Delegate::StatusCode aReason);
|
||||
void cancelDownload(InstallRef aInstall);
|
||||
|
||||
void registerInstall(InstallRef ins);
|
||||
void unregisterInstall(InstallRef ins);
|
||||
|
||||
class ThumbnailDownloader;
|
||||
class RootPrivate;
|
||||
std::auto_ptr<RootPrivate> d;
|
||||
};
|
||||
|
||||
@@ -34,22 +34,28 @@ bool keepRunning = true;
|
||||
class MyDelegate : public pkg::Delegate
|
||||
{
|
||||
public:
|
||||
virtual void refreshComplete()
|
||||
virtual void catalogRefreshed(pkg::CatalogRef aCatalog, StatusCode aReason)
|
||||
{
|
||||
if (aReason == STATUS_REFRESHED) {
|
||||
if (aCatalog.ptr() == NULL) {
|
||||
cout << "refreshed all catalogs" << endl;
|
||||
} else {
|
||||
cout << "refreshed catalog " << aCatalog->url() << endl;
|
||||
}
|
||||
} else if (aReason == STATUS_IN_PROGRESS) {
|
||||
cout << "started refresh of " << aCatalog->url() << endl;
|
||||
} else {
|
||||
cerr << "failed refresh of " << aCatalog->url() << ":" << aReason << endl;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void failedRefresh(pkg::Catalog* aCatalog, FailureCode aReason)
|
||||
{
|
||||
cerr << "failed refresh of " << aCatalog->description() << ":" << aReason << endl;
|
||||
}
|
||||
|
||||
virtual void startInstall(pkg::Install* aInstall)
|
||||
virtual void startInstall(pkg::InstallRef aInstall)
|
||||
{
|
||||
_lastPercent = 999;
|
||||
cout << "starting install of " << aInstall->package()->name() << endl;
|
||||
}
|
||||
|
||||
virtual void installProgress(pkg::Install* aInstall, unsigned int bytes, unsigned int total)
|
||||
virtual void installProgress(pkg::InstallRef aInstall, unsigned int bytes, unsigned int total)
|
||||
{
|
||||
unsigned int percent = (bytes * 100) / total;
|
||||
if (percent == _lastPercent) {
|
||||
@@ -60,15 +66,15 @@ public:
|
||||
cout << percent << "%" << endl;
|
||||
}
|
||||
|
||||
virtual void finishInstall(pkg::Install* aInstall)
|
||||
virtual void finishInstall(pkg::InstallRef aInstall, StatusCode aReason)
|
||||
{
|
||||
cout << "done install of " << aInstall->package()->name() << endl;
|
||||
if (aReason == STATUS_SUCCESS) {
|
||||
cout << "done install of " << aInstall->package()->name() << endl;
|
||||
} else {
|
||||
cerr << "failed install of " << aInstall->package()->name() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void failedInstall(pkg::Install* aInstall, FailureCode aReason)
|
||||
{
|
||||
cerr << "failed install of " << aInstall->package()->name() << endl;
|
||||
}
|
||||
private:
|
||||
unsigned int _lastPercent;
|
||||
|
||||
@@ -119,7 +125,7 @@ int main(int argc, char** argv)
|
||||
pkg::Root* root = new pkg::Root(Dir::current().path(), "");
|
||||
|
||||
MyDelegate dlg;
|
||||
root->setDelegate(&dlg);
|
||||
root->addDelegate(&dlg);
|
||||
|
||||
cout << "Package root is:" << Dir::current().path() << endl;
|
||||
cout << "have " << root->catalogs().size() << " catalog(s)" << endl;
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#endif
|
||||
|
||||
#include "props.hxx"
|
||||
#include "PropertyInterpolationMgr.hxx"
|
||||
#include "vectorPropTemplates.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
@@ -24,31 +22,30 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boost/algorithm/string/find_iterator.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#if PROPS_STANDALONE
|
||||
#include <iostream>
|
||||
# include <iostream>
|
||||
using std::cerr;
|
||||
#else
|
||||
# include <boost/algorithm/string/find_iterator.hpp>
|
||||
# include <boost/algorithm/string/predicate.hpp>
|
||||
# include <boost/algorithm/string/classification.hpp>
|
||||
# include <boost/bind.hpp>
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/range.hpp>
|
||||
# include <simgear/compiler.h>
|
||||
# include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
# include "PropertyInterpolationMgr.hxx"
|
||||
# include "vectorPropTemplates.hxx"
|
||||
|
||||
#if ( _MSC_VER == 1200 )
|
||||
# if ( _MSC_VER == 1200 )
|
||||
// MSVC 6 is buggy, and needs something strange here
|
||||
using std::vector<SGPropertyNode_ptr>;
|
||||
using std::vector<SGPropertyChangeListener *>;
|
||||
using std::vector<SGPropertyNode *>;
|
||||
#endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if PROPS_STANDALONE
|
||||
using std::cerr;
|
||||
#endif
|
||||
using std::endl;
|
||||
using std::find;
|
||||
using std::sort;
|
||||
@@ -84,6 +81,14 @@ public:
|
||||
// Local path normalization code.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if PROPS_STANDALONE
|
||||
struct PathComponent
|
||||
{
|
||||
string name;
|
||||
int index;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Parse the name for a path component.
|
||||
*
|
||||
@@ -146,10 +151,149 @@ inline bool validateName(const std::string& name)
|
||||
return false;
|
||||
if (!isalpha(name[0]) && name[0] != '_')
|
||||
return false;
|
||||
#if PROPS_STANDALONE
|
||||
std::string is_any_of("_-.");
|
||||
bool rv = true;
|
||||
for(unsigned i=1; i<name.length(); ++i) {
|
||||
if (!isalnum(name[i]) && is_any_of.find(name[i]) == std::string::npos) {
|
||||
rv = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
return all(make_iterator_range(name.begin(), name.end()),
|
||||
is_alnum() || is_any_of("_-."));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PROPS_STANDALONE
|
||||
/**
|
||||
* Parse the name for a path component.
|
||||
*
|
||||
* Name: [_a-zA-Z][-._a-zA-Z0-9]*
|
||||
*/
|
||||
static inline const string
|
||||
parse_name (const string &path, int &i)
|
||||
{
|
||||
string name = "";
|
||||
int max = (int)path.size();
|
||||
|
||||
if (path[i] == '.') {
|
||||
i++;
|
||||
if (i < max && path[i] == '.') {
|
||||
i++;
|
||||
name = "..";
|
||||
} else {
|
||||
name = ".";
|
||||
}
|
||||
if (i < max && path[i] != '/')
|
||||
throw string("Illegal character after " + name);
|
||||
}
|
||||
|
||||
else if (isalpha(path[i]) || path[i] == '_') {
|
||||
name += path[i];
|
||||
i++;
|
||||
|
||||
// The rules inside a name are a little
|
||||
// less restrictive.
|
||||
while (i < max) {
|
||||
if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
|
||||
path[i] == '-' || path[i] == '.') {
|
||||
name += path[i];
|
||||
} else if (path[i] == '[' || path[i] == '/') {
|
||||
break;
|
||||
} else {
|
||||
throw string("name may contain only ._- and alphanumeric characters");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (name.size() == 0)
|
||||
throw string("name must begin with alpha or '_'");
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the optional integer index for a path component.
|
||||
*
|
||||
* Index: "[" [0-9]+ "]"
|
||||
*/
|
||||
static inline int
|
||||
parse_index (const string &path, int &i)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
if (path[i] != '[')
|
||||
return 0;
|
||||
else
|
||||
i++;
|
||||
|
||||
for (int max = (int)path.size(); i < max; i++) {
|
||||
if (isdigit(path[i])) {
|
||||
index = (index * 10) + (path[i] - '0');
|
||||
} else if (path[i] == ']') {
|
||||
i++;
|
||||
return index;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
throw string("unterminated index (looking for ']')");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single path component.
|
||||
*
|
||||
* Component: Name Index?
|
||||
*/
|
||||
static inline PathComponent
|
||||
parse_component (const string &path, int &i)
|
||||
{
|
||||
PathComponent component;
|
||||
component.name = parse_name(path, i);
|
||||
if (component.name[0] != '.')
|
||||
component.index = parse_index(path, i);
|
||||
else
|
||||
component.index = -1;
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a path into its components.
|
||||
*/
|
||||
static void
|
||||
parse_path (const string &path, vector<PathComponent> &components)
|
||||
{
|
||||
int pos = 0;
|
||||
int max = (int)path.size();
|
||||
|
||||
// Check for initial '/'
|
||||
if (path[pos] == '/') {
|
||||
PathComponent root;
|
||||
root.name = "";
|
||||
root.index = -1;
|
||||
components.push_back(root);
|
||||
pos++;
|
||||
while (pos < max && path[pos] == '/')
|
||||
pos++;
|
||||
}
|
||||
|
||||
while (pos < max) {
|
||||
components.push_back(parse_component(path, pos));
|
||||
while (pos < max && path[pos] == '/')
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Other static utility functions.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -182,6 +326,13 @@ static int
|
||||
find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
|
||||
{
|
||||
size_t nNodes = nodes.size();
|
||||
#if PROPS_STANDALONE
|
||||
for (int i = 0; i < nNodes; i++) {
|
||||
SGPropertyNode * node = nodes[i];
|
||||
if (node->getIndex() == index && compare_strings(node->getName(), begin))
|
||||
return i;
|
||||
}
|
||||
#else
|
||||
boost::iterator_range<Itr> name(begin, end);
|
||||
for (size_t i = 0; i < nNodes; i++) {
|
||||
SGPropertyNode * node = nodes[i];
|
||||
@@ -191,6 +342,7 @@ find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
|
||||
if (node->getIndex() == index && boost::equals(node->getName(), name))
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -333,11 +485,57 @@ find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create,
|
||||
|
||||
// Internal function for parsing property paths. last_index provides
|
||||
// and index value for the last node name token, if supplied.
|
||||
#if PROPS_STANDALONE
|
||||
static SGPropertyNode *
|
||||
find_node (SGPropertyNode * current,
|
||||
const vector<PathComponent> &components,
|
||||
int position,
|
||||
bool create)
|
||||
{
|
||||
// Run off the end of the list
|
||||
if (current == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Success! This is the one we want.
|
||||
else if (position >= (int)components.size()) {
|
||||
return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
|
||||
}
|
||||
|
||||
// Empty component means root.
|
||||
else if (components[position].name == "") {
|
||||
return find_node(current->getRootNode(), components, position + 1, create);
|
||||
}
|
||||
|
||||
// . means current directory
|
||||
else if (components[position].name == ".") {
|
||||
return find_node(current, components, position + 1, create);
|
||||
}
|
||||
|
||||
// .. means parent directory
|
||||
else if (components[position].name == "..") {
|
||||
SGPropertyNode * parent = current->getParent();
|
||||
if (parent == 0)
|
||||
throw string("Attempt to move past root with '..'");
|
||||
else
|
||||
return find_node(parent, components, position + 1, create);
|
||||
}
|
||||
|
||||
// Otherwise, a child name
|
||||
else {
|
||||
SGPropertyNode * child =
|
||||
current->getChild(components[position].name.c_str(),
|
||||
components[position].index,
|
||||
create);
|
||||
return find_node(child, components, position + 1, create);
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename Range>
|
||||
SGPropertyNode*
|
||||
find_node (SGPropertyNode * current,
|
||||
const Range& path,
|
||||
bool create,
|
||||
bool create,
|
||||
int last_index = -1)
|
||||
{
|
||||
using namespace boost;
|
||||
@@ -351,6 +549,7 @@ find_node (SGPropertyNode * current,
|
||||
else
|
||||
return find_node_aux(current, itr, create, last_index);
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Private methods from SGPropertyNode (may be inlined for speed).
|
||||
@@ -611,13 +810,8 @@ SGPropertyNode::make_string () const
|
||||
void
|
||||
SGPropertyNode::trace_write () const
|
||||
{
|
||||
#if PROPS_STANDALONE
|
||||
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||
<< make_string() << '"' << endl;
|
||||
#else
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
|
||||
<< ", value \"" << make_string() << '"');
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -626,13 +820,8 @@ SGPropertyNode::trace_write () const
|
||||
void
|
||||
SGPropertyNode::trace_read () const
|
||||
{
|
||||
#if PROPS_STANDALONE
|
||||
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||
<< make_string() << '"' << endl;
|
||||
#else
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
|
||||
<< ", value \"" << make_string() << '"');
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -786,8 +975,6 @@ SGPropertyNode::alias (SGPropertyNode * target)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if PROPS_STANDALONE
|
||||
#else
|
||||
if (!target)
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||
@@ -809,7 +996,6 @@ SGPropertyNode::alias (SGPropertyNode * target)
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". "
|
||||
"Source " << getPath() << " is a tied property.");
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -957,11 +1143,18 @@ SGPropertyNode::getChild (const char * name, int index, bool create)
|
||||
SGPropertyNode *
|
||||
SGPropertyNode::getChild (const std::string& name, int index, bool create)
|
||||
{
|
||||
#if PROPS_STANDALONE
|
||||
const char *n = name.c_str();
|
||||
int pos = find_child(n, n + strlen(n), index, _children);
|
||||
if (pos >= 0) {
|
||||
return _children[pos];
|
||||
#else
|
||||
SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index);
|
||||
if (node) {
|
||||
return node;
|
||||
#endif
|
||||
} else if (create) {
|
||||
node = new SGPropertyNode(name, index, this);
|
||||
SGPropertyNode* node = new SGPropertyNode(name, index, this);
|
||||
_children.push_back(node);
|
||||
fireChildAdded(node);
|
||||
return node;
|
||||
@@ -1635,12 +1828,14 @@ SGPropertyNode::setUnspecifiedValue (const char * value)
|
||||
case props::UNSPECIFIED:
|
||||
result = set_string(value);
|
||||
break;
|
||||
#if !PROPS_STANDALONE
|
||||
case props::VEC3D:
|
||||
result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
|
||||
break;
|
||||
case props::VEC4D:
|
||||
result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
|
||||
break;
|
||||
#endif
|
||||
case props::NONE:
|
||||
default:
|
||||
break;
|
||||
@@ -1652,6 +1847,7 @@ SGPropertyNode::setUnspecifiedValue (const char * value)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#if !PROPS_STANDALONE
|
||||
bool SGPropertyNode::interpolate( const std::string& type,
|
||||
const SGPropertyNode& target,
|
||||
double duration,
|
||||
@@ -1701,6 +1897,7 @@ simgear::PropertyInterpolationMgr* SGPropertyNode::getInterpolationMgr()
|
||||
}
|
||||
|
||||
simgear::PropertyInterpolationMgr* SGPropertyNode::_interpolation_mgr = 0;
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
|
||||
@@ -1854,20 +2051,37 @@ SGPropertyNode::getRootNode () const
|
||||
SGPropertyNode *
|
||||
SGPropertyNode::getNode (const char * relative_path, bool create)
|
||||
{
|
||||
#if PROPS_STANDALONE
|
||||
vector<PathComponent> components;
|
||||
parse_path(relative_path, components);
|
||||
return find_node(this, components, 0, create);
|
||||
|
||||
#else
|
||||
using namespace boost;
|
||||
|
||||
return find_node(this, make_iterator_range(relative_path, relative_path
|
||||
+ strlen(relative_path)),
|
||||
create);
|
||||
#endif
|
||||
}
|
||||
|
||||
SGPropertyNode *
|
||||
SGPropertyNode::getNode (const char * relative_path, int index, bool create)
|
||||
{
|
||||
#if PROPS_STANDALONE
|
||||
vector<PathComponent> components;
|
||||
parse_path(relative_path, components);
|
||||
if (components.size() > 0)
|
||||
components.back().index = index;
|
||||
return find_node(this, components, 0, create);
|
||||
|
||||
#else
|
||||
using namespace boost;
|
||||
|
||||
return find_node(this, make_iterator_range(relative_path, relative_path
|
||||
+ strlen(relative_path)),
|
||||
create, index);
|
||||
#endif
|
||||
}
|
||||
|
||||
const SGPropertyNode *
|
||||
@@ -2315,6 +2529,7 @@ SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
|
||||
_properties.erase(it);
|
||||
}
|
||||
|
||||
#if !PROPS_STANDALONE
|
||||
template<>
|
||||
std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
|
||||
{
|
||||
@@ -2351,9 +2566,11 @@ std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
#if !PROPS_STANDALONE
|
||||
template<>
|
||||
std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
|
||||
{
|
||||
@@ -2362,6 +2579,7 @@ std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -2389,10 +2607,12 @@ bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
|
||||
case props::STRING:
|
||||
case props::UNSPECIFIED:
|
||||
return !strcmp(lhs.getStringValue(), rhs.getStringValue());
|
||||
#if !PROPS_STANDALONE
|
||||
case props::VEC3D:
|
||||
return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
|
||||
case props::VEC4D:
|
||||
return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -2449,10 +2669,10 @@ struct PropertyPlaceLess {
|
||||
}
|
||||
};
|
||||
|
||||
#if !PROPS_STANDALONE
|
||||
size_t hash_value(const SGPropertyNode& node)
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
if (node.nChildren() == 0) {
|
||||
switch (node.getType()) {
|
||||
case props::NONE:
|
||||
@@ -2503,5 +2723,6 @@ size_t hash_value(const SGPropertyNode& node)
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// end of props.cxx
|
||||
|
||||
@@ -22,24 +22,54 @@
|
||||
#include <sstream>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/type_traits/is_enum.hpp>
|
||||
|
||||
#if PROPS_STANDALONE
|
||||
#else
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#if PROPS_STANDALONE
|
||||
// taken from: boost/utility/enable_if.hpp
|
||||
#ifndef SG_LOG
|
||||
# define SG_GENERAL 0
|
||||
# define SG_ALERT 0
|
||||
# define SG_WARN 1
|
||||
# define SG_LOG(type, level, message) (type) ? (std::cerr <<message << endl) : (std::cout <<message << endl)
|
||||
#endif
|
||||
namespace boost {
|
||||
template <bool B, class T = void>
|
||||
struct enable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct enable_if_c<false, T> {};
|
||||
|
||||
#include <simgear/math/SGMathFwd.hxx>
|
||||
#include <simgear/math/sg_types.hxx>
|
||||
template <class Cond, class T = void>
|
||||
struct enable_if : public enable_if_c<Cond::value, T> {};
|
||||
|
||||
template <bool B, class T = void>
|
||||
struct disable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct disable_if_c<true, T> {};
|
||||
|
||||
template <class Cond, class T = void>
|
||||
struct disable_if : public disable_if_c<Cond::value, T> {};
|
||||
}
|
||||
#else
|
||||
# include <boost/utility.hpp>
|
||||
# include <boost/type_traits/is_enum.hpp>
|
||||
|
||||
# include <simgear/debug/logstream.hxx>
|
||||
# include <simgear/math/SGMathFwd.hxx>
|
||||
# include <simgear/math/sg_types.hxx>
|
||||
#endif
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
// XXX This whole file should be in the simgear namespace, but I don't
|
||||
// have the guts yet...
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
@@ -1275,6 +1305,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !PROPS_STANDALONE
|
||||
/**
|
||||
* Interpolate current value to target value within given time.
|
||||
*
|
||||
@@ -1310,6 +1341,7 @@ public:
|
||||
* Get the interpolation manager
|
||||
*/
|
||||
static simgear::PropertyInterpolationMgr* getInterpolationMgr();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Print the value of the property to a stream.
|
||||
@@ -1807,7 +1839,11 @@ private:
|
||||
|
||||
// Convenience functions for use in templates
|
||||
template<typename T>
|
||||
#if PROPS_STANDALONE
|
||||
T
|
||||
#else
|
||||
typename boost::disable_if<boost::is_enum<T>, T>::type
|
||||
#endif
|
||||
getValue(const SGPropertyNode*);
|
||||
|
||||
template<>
|
||||
@@ -1871,7 +1907,11 @@ namespace simgear
|
||||
|
||||
/** Extract enum from SGPropertyNode */
|
||||
template<typename T>
|
||||
#if PROPS_STANDALONE
|
||||
inline T
|
||||
#else
|
||||
inline typename boost::enable_if<boost::is_enum<T>, T>::type
|
||||
#endif
|
||||
getValue(const SGPropertyNode* node)
|
||||
{
|
||||
typedef simgear::enum_traits<T> Traits;
|
||||
|
||||
@@ -201,7 +201,7 @@ SGMaterialCache *SGMaterialLib::generateMatCache(SGGeod center)
|
||||
|
||||
// Destructor
|
||||
SGMaterialLib::~SGMaterialLib ( void ) {
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialLib::~SGMaterialLib() size=" << matlib.size());
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialLib::~SGMaterialLib() size=" << matlib.size());
|
||||
}
|
||||
|
||||
const SGMaterial *SGMaterialLib::findMaterial(const osg::Geode* geode)
|
||||
@@ -244,5 +244,5 @@ SGMaterial *SGMaterialCache::find(const string& material) const
|
||||
|
||||
// Destructor
|
||||
SGMaterialCache::~SGMaterialCache ( void ) {
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
|
||||
}
|
||||
|
||||
@@ -364,6 +364,8 @@ public:
|
||||
if (_textureProp) {
|
||||
std::string textureName = _textureProp->getStringValue();
|
||||
if (_textureName != textureName) {
|
||||
_textureName = textureName;
|
||||
|
||||
while (stateSet->getTextureAttribute(0,
|
||||
osg::StateAttribute::TEXTURE)) {
|
||||
stateSet->removeTextureAttribute(0, osg::StateAttribute::TEXTURE);
|
||||
@@ -377,8 +379,12 @@ public:
|
||||
osg::StateAttribute::OVERRIDE);
|
||||
stateSet->setTextureMode(0, GL_TEXTURE_2D,
|
||||
osg::StateAttribute::ON);
|
||||
_textureName = textureName;
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_IO, SG_WARN, "texture animation: requested texture : " << textureName << " not found. Searched paths:" );
|
||||
for( osgDB::FilePathList::iterator it = _texturePathList.begin(); it != _texturePathList.end(); ++it ) {
|
||||
SG_LOG(SG_IO, SG_WARN, " - " << *it );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ SGModelLib::panel_func SGModelLib::static_panelFunc = NULL;
|
||||
void SGModelLib::init(const string &root_dir, SGPropertyNode* root)
|
||||
{
|
||||
osgDB::Registry::instance()->getDataFilePathList().push_front(root_dir);
|
||||
osgDB::Registry::instance()->getOptions()->getDatabasePathList().push_front(root_dir);
|
||||
static_propRoot = root;
|
||||
}
|
||||
|
||||
@@ -114,6 +115,7 @@ SGModelLib::loadModel(const string &path,
|
||||
{
|
||||
osg::ref_ptr<SGReaderWriterOptions> opt;
|
||||
opt = SGReaderWriterOptions::copyOrCreate(osgDB::Registry::instance()->getOptions());
|
||||
opt->getDatabasePathList().push_front( osgDB::getFilePath(path) );
|
||||
opt->setPropertyNode(prop_root ? prop_root: static_propRoot.get());
|
||||
opt->setModelData(data);
|
||||
|
||||
@@ -136,8 +138,10 @@ SGModelLib::loadDeferredModel(const string &path, SGPropertyNode *prop_root,
|
||||
proxyNode->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
|
||||
proxyNode->setFileName(0, path);
|
||||
|
||||
|
||||
osg::ref_ptr<SGReaderWriterOptions> opt;
|
||||
opt = SGReaderWriterOptions::copyOrCreate(osgDB::Registry::instance()->getOptions());
|
||||
opt->getDatabasePathList().push_front( osgDB::getFilePath(path) );
|
||||
opt->setPropertyNode(prop_root ? prop_root: static_propRoot.get());
|
||||
opt->setModelData(data);
|
||||
opt->setLoadPanel(static_panelFunc);
|
||||
|
||||
@@ -216,6 +216,46 @@ SGSun::build( SGPath path, double sun_size, SGPropertyNode *property_tree_Node )
|
||||
|
||||
sun_transform->addChild( geode );
|
||||
|
||||
|
||||
// set up the brilliance state
|
||||
|
||||
geode = new osg::Geode;
|
||||
stateSet = geode->getOrCreateStateSet();
|
||||
stateSet->setRenderBinDetails(-9, "RenderBin");
|
||||
|
||||
|
||||
texture = SGLoadTexture2D("brilliance.png", options.get());
|
||||
stateSet->setTextureAttributeAndModes(0, texture);
|
||||
|
||||
|
||||
// Build ssg structure
|
||||
brilliance_cl = new osg::Vec4Array;
|
||||
brilliance_cl->push_back(osg::Vec4(1, 1, 1, 1));
|
||||
|
||||
double brilliance_size = sun_size * 12.0;
|
||||
osg::Vec3Array* brilliance_vl = new osg::Vec3Array;
|
||||
brilliance_vl->push_back(osg::Vec3(-brilliance_size, 0, -brilliance_size));
|
||||
brilliance_vl->push_back(osg::Vec3(brilliance_size, 0, -brilliance_size));
|
||||
brilliance_vl->push_back(osg::Vec3(-brilliance_size, 0, brilliance_size));
|
||||
brilliance_vl->push_back(osg::Vec3(brilliance_size, 0, brilliance_size));
|
||||
|
||||
osg::Vec2Array* brilliance_tl = new osg::Vec2Array;
|
||||
brilliance_tl->push_back(osg::Vec2(0, 0));
|
||||
brilliance_tl->push_back(osg::Vec2(1, 0));
|
||||
brilliance_tl->push_back(osg::Vec2(0, 1));
|
||||
brilliance_tl->push_back(osg::Vec2(1, 1));
|
||||
|
||||
geometry = new osg::Geometry;
|
||||
geometry->setUseDisplayList(false);
|
||||
geometry->setVertexArray(brilliance_vl);
|
||||
geometry->setColorArray(brilliance_cl.get(), osg::Array::BIND_OVERALL);
|
||||
geometry->setNormalBinding(osg::Geometry::BIND_OFF);
|
||||
geometry->setTexCoordArray(0, brilliance_tl, osg::Array::BIND_PER_VERTEX);
|
||||
geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
|
||||
geode->addDrawable(geometry);
|
||||
|
||||
sun_transform->addChild( geode );
|
||||
|
||||
// force a repaint of the sun colors with arbitrary defaults
|
||||
repaint( 0.0, 1.0 );
|
||||
|
||||
@@ -262,7 +302,7 @@ bool SGSun::repaint( double sun_angle, double new_visibility ) {
|
||||
}
|
||||
|
||||
// ok, now let's go and generate the sun and scene color
|
||||
osg::Vec4 i_halo_color, o_halo_color, scene_color, sun_color;
|
||||
osg::Vec4 i_halo_color, o_halo_color, scene_color, sun_color, brilliance_color;
|
||||
|
||||
// Some comments:
|
||||
// * When the sunangle changes, light has to travel a longer
|
||||
@@ -336,16 +376,29 @@ bool SGSun::repaint( double sun_angle, double new_visibility ) {
|
||||
if (o_halo_color[3] > 1) o_halo_color[3] = 1;
|
||||
if (o_halo_color[3] < 0) o_halo_color[3] = 0;
|
||||
|
||||
brilliance_color[0] = i_halo_color[0];
|
||||
brilliance_color[1] = i_halo_color[1];
|
||||
brilliance_color[2] = i_halo_color[2];
|
||||
|
||||
double norm = (i_halo_color[0] * i_halo_color[0] + i_halo_color[1] * i_halo_color[1] + i_halo_color[2] * i_halo_color[2])/1.732;
|
||||
|
||||
brilliance_color[3] = pow(norm, 6.0);
|
||||
if (brilliance_color[3] < 0.0) {brilliance_color[3] = 0.0;}
|
||||
|
||||
|
||||
|
||||
gamma_correct_rgb( i_halo_color._v );
|
||||
gamma_correct_rgb( o_halo_color._v );
|
||||
gamma_correct_rgb( scene_color._v );
|
||||
gamma_correct_rgb( sun_color._v );
|
||||
gamma_correct_rgb( brilliance_color._v );
|
||||
|
||||
if (sun_angle >91.0 * 3.1415/180.0 + horizon_angle)
|
||||
{
|
||||
sun_color[3] = 0;
|
||||
o_halo_color[3]=0;
|
||||
i_halo_color[3]=0;
|
||||
brilliance_color[3]=0;
|
||||
}
|
||||
|
||||
(*sun_cl)[0] = sun_color;
|
||||
@@ -356,6 +409,8 @@ bool SGSun::repaint( double sun_angle, double new_visibility ) {
|
||||
ihalo_cl->dirty();
|
||||
(*ohalo_cl)[0] = o_halo_color;
|
||||
ohalo_cl->dirty();
|
||||
(*brilliance_cl)[0] = brilliance_color;
|
||||
brilliance_cl->dirty();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -372,19 +427,14 @@ bool SGSun::reposition( double rightAscension, double declination,
|
||||
{
|
||||
// GST - GMT sidereal time
|
||||
osg::Matrix T2, RA, DEC;
|
||||
|
||||
// xglRotatef( ((SGD_RADIANS_TO_DEGREES * rightAscension)- 90.0),
|
||||
// 0.0, 0.0, 1.0);
|
||||
RA.makeRotate(rightAscension - 90*SGD_DEGREES_TO_RADIANS, osg::Vec3(0, 0, 1));
|
||||
|
||||
// xglRotatef((SGD_RADIANS_TO_DEGREES * declination), 1.0, 0.0, 0.0);
|
||||
DEC.makeRotate(declination, osg::Vec3(1, 0, 0));
|
||||
|
||||
// xglTranslatef(0,sun_dist);
|
||||
T2.makeTranslate(osg::Vec3(0, sun_dist, 0));
|
||||
|
||||
sun_transform->setMatrix(T2*DEC*RA);
|
||||
|
||||
// Suncolor related things:
|
||||
if ( prev_sun_angle != sun_angle ) {
|
||||
if ( sun_angle == 0 ) sun_angle = 0.1;
|
||||
@@ -412,7 +462,7 @@ bool SGSun::reposition( double rightAscension, double declination,
|
||||
if ( alt_half < 0.0 ) alt_half = 0.0;
|
||||
|
||||
//angle at which the sun is visible below the horizon
|
||||
horizon_angle = acos(r_earth/position_radius);
|
||||
horizon_angle = acos(min(r_earth/position_radius, 1.0));
|
||||
|
||||
// Push the data to the property tree, so it can be used in the enviromental code
|
||||
if ( env_node ){
|
||||
|
||||
@@ -45,6 +45,7 @@ class SGSun : public SGReferenced {
|
||||
osg::ref_ptr<osg::Vec4Array> scene_cl;
|
||||
osg::ref_ptr<osg::Vec4Array> ihalo_cl;
|
||||
osg::ref_ptr<osg::Vec4Array> ohalo_cl;
|
||||
osg::ref_ptr<osg::Vec4Array> brilliance_cl;
|
||||
|
||||
double visibility;
|
||||
double prev_sun_angle;
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/scene/util/OptionsReadFileCallback.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
#include <simgear/scene/util/QuadTreeBuilder.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||
#include <simgear/scene/tgdb/apt_signs.hxx>
|
||||
@@ -113,48 +114,79 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
};
|
||||
|
||||
class DelayLoadReadFileCallback : public OptionsReadFileCallback {
|
||||
|
||||
private:
|
||||
// QuadTreeBuilder for structuring static objects
|
||||
struct MakeQuadLeaf {
|
||||
osg::LOD* operator() () const { return new osg::LOD; }
|
||||
};
|
||||
struct AddModelLOD {
|
||||
void operator() (osg::LOD* leaf, _ObjectStatic o) const
|
||||
{
|
||||
osg::ref_ptr<osg::Node> node;
|
||||
if (o._proxy) {
|
||||
osg::ref_ptr<osg::ProxyNode> proxy = new osg::ProxyNode;
|
||||
proxy->setName("proxyNode");
|
||||
proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
|
||||
proxy->setFileName(0, o._name);
|
||||
proxy->setDatabaseOptions(o._options.get());
|
||||
|
||||
// Give the node some values so the Quadtree builder has
|
||||
// a BoundingBox to work with prior to the model being loaded.
|
||||
proxy->setCenter(osg::Vec3f(0.0f,0.0f,0.0f));
|
||||
proxy->setRadius(10);
|
||||
proxy->setCenterMode(osg::ProxyNode::UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED);
|
||||
node = proxy;
|
||||
} else {
|
||||
node = osgDB::readRefNodeFile(o._name, o._options.get());
|
||||
if (!node.valid()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, o._errorLocation << ": Failed to load "
|
||||
<< o._token << " '" << o._name << "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (SGPath(o._name).lower_extension() == "ac")
|
||||
node->setNodeMask(~simgear::MODELLIGHT_BIT);
|
||||
|
||||
osg::Matrix matrix;
|
||||
matrix = makeZUpFrame(SGGeod::fromDegM(o._lon, o._lat, o._elev));
|
||||
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(o._hdg), osg::Vec3(0, 0, 1)));
|
||||
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(o._pitch), osg::Vec3(0, 1, 0)));
|
||||
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(o._roll), osg::Vec3(1, 0, 0)));
|
||||
|
||||
osg::MatrixTransform* matrixTransform;
|
||||
matrixTransform = new osg::MatrixTransform(matrix);
|
||||
matrixTransform->setName("rotateStaticObject");
|
||||
matrixTransform->setDataVariance(osg::Object::STATIC);
|
||||
matrixTransform->addChild(node.get());
|
||||
leaf->addChild(matrixTransform, 0, 20000); //TODO: Make configurable?
|
||||
}
|
||||
};
|
||||
struct GetModelLODCoord {
|
||||
GetModelLODCoord() {}
|
||||
GetModelLODCoord(const GetModelLODCoord& rhs)
|
||||
{}
|
||||
osg::Vec3 operator() (const _ObjectStatic& o) const
|
||||
{
|
||||
SGVec3d coord;
|
||||
SGGeodesy::SGGeodToCart(SGGeod::fromDegM(o._lon, o._lat, o._elev), coord);
|
||||
return toOsg(coord);
|
||||
}
|
||||
};
|
||||
typedef QuadTreeBuilder<osg::LOD*, _ObjectStatic, MakeQuadLeaf, AddModelLOD,
|
||||
GetModelLODCoord> STGObjectsQuadtree;
|
||||
|
||||
|
||||
public:
|
||||
virtual osgDB::ReaderWriter::ReadResult
|
||||
readNode(const std::string&, const osgDB::Options*)
|
||||
{
|
||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
|
||||
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
|
||||
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
|
||||
group->setName("STG-group-A");
|
||||
group->setDataVariance(osg::Object::STATIC);
|
||||
|
||||
for (std::list<_ObjectStatic>::iterator i = _objectStaticList.begin(); i != _objectStaticList.end(); ++i) {
|
||||
osg::ref_ptr<osg::Node> node;
|
||||
if (i->_proxy) {
|
||||
osg::ref_ptr<osg::ProxyNode> proxy = new osg::ProxyNode;
|
||||
proxy->setName("proxyNode");
|
||||
proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
|
||||
proxy->setFileName(0, i->_name);
|
||||
proxy->setDatabaseOptions(i->_options.get());
|
||||
node = proxy;
|
||||
} else {
|
||||
node = osgDB::readRefNodeFile(i->_name, i->_options.get());
|
||||
if (!node.valid()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, i->_errorLocation << ": Failed to load "
|
||||
<< i->_token << " '" << i->_name << "'");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (SGPath(i->_name).lower_extension() == "ac")
|
||||
node->setNodeMask(~simgear::MODELLIGHT_BIT);
|
||||
|
||||
osg::Matrix matrix;
|
||||
matrix = makeZUpFrame(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev));
|
||||
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_hdg), osg::Vec3(0, 0, 1)));
|
||||
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_pitch), osg::Vec3(0, 1, 0)));
|
||||
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_roll), osg::Vec3(1, 0, 0)));
|
||||
|
||||
osg::MatrixTransform* matrixTransform;
|
||||
matrixTransform = new osg::MatrixTransform(matrix);
|
||||
matrixTransform->setName("positionStaticObject");
|
||||
matrixTransform->setDataVariance(osg::Object::STATIC);
|
||||
matrixTransform->addChild(node.get());
|
||||
group->addChild(matrixTransform);
|
||||
}
|
||||
|
||||
|
||||
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
|
||||
for (std::list<_Sign>::iterator i = _signList.begin(); i != _signList.end(); ++i)
|
||||
signBuilder.addSign(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev), i->_hdg, i->_name, i->_size);
|
||||
@@ -266,7 +298,7 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
// read a line
|
||||
std::string line;
|
||||
std::getline(stream, line);
|
||||
|
||||
|
||||
// strip comments
|
||||
std::string::size_type hash_pos = line.find('#');
|
||||
if (hash_pos != std::string::npos)
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
virtual ~SGTileDetailsCallback()
|
||||
{
|
||||
num_tdcb--;
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "SGTileDetailsCallback::~SGTileDetailsCallback() num cbs left " << num_tdcb );
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGTileDetailsCallback::~SGTileDetailsCallback() num cbs left " << num_tdcb );
|
||||
}
|
||||
|
||||
virtual osgDB::ReaderWriter::ReadResult readNode(
|
||||
@@ -736,9 +736,9 @@ public:
|
||||
if (!found) {
|
||||
bin = new TreeBin();
|
||||
bin->texture = mat->get_tree_texture();
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Tree texture " << bin->texture);
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Tree texture " << bin->texture);
|
||||
bin->teffect = mat->get_tree_effect();
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Tree effect " << bin->teffect);
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Tree effect " << bin->teffect);
|
||||
bin->range = mat->get_tree_range();
|
||||
bin->width = mat->get_tree_width();
|
||||
bin->height = mat->get_tree_height();
|
||||
@@ -789,11 +789,6 @@ public:
|
||||
float coverage = mat->get_light_coverage();
|
||||
if (coverage <= 0)
|
||||
continue;
|
||||
if (coverage < 10000.0) {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
|
||||
<< coverage << ", pushing up to 10000");
|
||||
coverage = 10000;
|
||||
}
|
||||
|
||||
int texIndex = matTris[i].getTextureIndex();
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <map>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/version.h>
|
||||
|
||||
#include "terrasync.hxx"
|
||||
|
||||
@@ -228,7 +229,7 @@ protected:
|
||||
|
||||
virtual void onFail()
|
||||
{
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Failed to query TerraSync SVN server");
|
||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "Failed to query TerraSync SVN server");
|
||||
HTTP::Request::onFail();
|
||||
}
|
||||
|
||||
@@ -343,7 +344,7 @@ SGTerraSync::SvnThread::SvnThread() :
|
||||
_stop(false),
|
||||
_use_svn(true)
|
||||
{
|
||||
_http.setUserAgent("terrascenery-" SG_STRINGIZE(SG_VERSION));
|
||||
_http.setUserAgent("terrascenery-" SG_STRINGIZE(SIMGEAR_VERSION));
|
||||
}
|
||||
|
||||
void SGTerraSync::SvnThread::stop()
|
||||
@@ -369,7 +370,7 @@ bool SGTerraSync::SvnThread::start()
|
||||
|
||||
if (_local_dir=="")
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Cannot start scenery download. Local cache directory is undefined.");
|
||||
_fail_count++;
|
||||
_stalled = true;
|
||||
@@ -379,7 +380,7 @@ bool SGTerraSync::SvnThread::start()
|
||||
SGPath path(_local_dir);
|
||||
if (!path.exists())
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Cannot start scenery download. Directory '" << _local_dir <<
|
||||
"' does not exist. Set correct directory path or create directory folder.");
|
||||
_fail_count++;
|
||||
@@ -390,7 +391,7 @@ bool SGTerraSync::SvnThread::start()
|
||||
path.append("version");
|
||||
if (path.exists())
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Cannot start scenery download. Directory '" << _local_dir <<
|
||||
"' contains the base package. Use a separate directory.");
|
||||
_fail_count++;
|
||||
@@ -403,7 +404,7 @@ bool SGTerraSync::SvnThread::start()
|
||||
|
||||
if ((!_use_svn)&&(_rsync_server==""))
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Cannot start scenery download. Rsync scenery server is undefined.");
|
||||
_fail_count++;
|
||||
_stalled = true;
|
||||
@@ -435,7 +436,7 @@ bool SGTerraSync::SvnThread::start()
|
||||
|
||||
// not really an alert - but we want to (always) see this message, so user is
|
||||
// aware we're downloading scenery (and using bandwidth).
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Starting automatic scenery download/synchronization. "
|
||||
<< status
|
||||
<< "Directory: '" << _local_dir << "'.");
|
||||
@@ -475,7 +476,7 @@ bool SGTerraSync::SvnThread::runExternalSyncCommand(const char* dir)
|
||||
#else
|
||||
command = buf.str();
|
||||
#endif
|
||||
SG_LOG(SG_TERRAIN,SG_DEBUG, "sync command '" << command << "'");
|
||||
SG_LOG(SG_TERRASYNC,SG_DEBUG, "sync command '" << command << "'");
|
||||
|
||||
#ifdef SG_WINDOWS
|
||||
// tbd: does Windows support "popen"?
|
||||
@@ -490,7 +491,7 @@ bool SGTerraSync::SvnThread::runExternalSyncCommand(const char* dir)
|
||||
|
||||
if (rc)
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Failed to synchronize directory '" << dir << "', " <<
|
||||
"error code= " << rc);
|
||||
return false;
|
||||
@@ -505,7 +506,7 @@ void SGTerraSync::SvnThread::run()
|
||||
|
||||
{
|
||||
if (_svn_server.empty()) {
|
||||
SG_LOG(SG_TERRAIN,SG_INFO, "Querying closest TerraSync server");
|
||||
SG_LOG(SG_TERRASYNC,SG_INFO, "Querying closest TerraSync server");
|
||||
ServerSelectQuery* ssq = new ServerSelectQuery;
|
||||
HTTP::Request_ptr req = ssq;
|
||||
_http.makeRequest(req);
|
||||
@@ -515,12 +516,12 @@ void SGTerraSync::SvnThread::run()
|
||||
|
||||
if (req->readyState() == HTTP::Request::DONE) {
|
||||
_svn_server = ssq->svnUrl();
|
||||
SG_LOG(SG_TERRAIN,SG_INFO, "Closest TerraSync server:" << _svn_server);
|
||||
SG_LOG(SG_TERRASYNC,SG_INFO, "Closest TerraSync server:" << _svn_server);
|
||||
} else {
|
||||
SG_LOG(SG_TERRAIN,SG_WARN, "Failed to query closest TerraSync server");
|
||||
SG_LOG(SG_TERRASYNC,SG_WARN, "Failed to query closest TerraSync server");
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_TERRAIN,SG_INFO, "Explicit: TerraSync server:" << _svn_server);
|
||||
SG_LOG(SG_TERRASYNC,SG_INFO, "Explicit: TerraSync server:" << _svn_server);
|
||||
}
|
||||
|
||||
if (_svn_server.empty()) {
|
||||
@@ -551,7 +552,7 @@ void SGTerraSync::SvnThread::runExternal()
|
||||
SyncItem::Status cacheStatus = isPathCached(next);
|
||||
if (cacheStatus != SyncItem::Invalid) {
|
||||
_cache_hits++;
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG,
|
||||
SG_LOG(SG_TERRASYNC, SG_DEBUG,
|
||||
"Cache hit for: '" << next._dir << "'");
|
||||
next._status = cacheStatus;
|
||||
_freshTiles.push_back(next);
|
||||
@@ -581,7 +582,7 @@ void SGTerraSync::SvnThread::syncPathExternal(const SyncItem& next)
|
||||
if (isNewDirectory) {
|
||||
int rc = path.create_dir( 0755 );
|
||||
if (rc) {
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Cannot create directory '" << path << "', return code = " << rc );
|
||||
throw sg_exception("Cannot create directory for terrasync", path.str());
|
||||
}
|
||||
@@ -605,9 +606,9 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
if (slot.repository.get()) {
|
||||
if (slot.repository->isDoingSync()) {
|
||||
#if 1
|
||||
if (slot.stamp.elapsedMSec() > slot.nextWarnTimeout) {
|
||||
SG_LOG(SG_TERRAIN, SG_INFO, "sync taking a long time:" << slot.currentItem._dir << " taken " << slot.stamp.elapsedMSec());
|
||||
SG_LOG(SG_TERRAIN, SG_INFO, "HTTP status:" << _http.hasActiveRequests());
|
||||
if (slot.stamp.elapsedMSec() > (int)slot.nextWarnTimeout) {
|
||||
SG_LOG(SG_TERRASYNC, SG_INFO, "sync taking a long time:" << slot.currentItem._dir << " taken " << slot.stamp.elapsedMSec());
|
||||
SG_LOG(SG_TERRASYNC, SG_INFO, "HTTP request count:" << _http.hasActiveRequests());
|
||||
slot.nextWarnTimeout += 10000;
|
||||
}
|
||||
#endif
|
||||
@@ -622,7 +623,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
fail(slot.currentItem);
|
||||
} else {
|
||||
updated(slot.currentItem, slot.isNewDirectory);
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
|
||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
|
||||
<< slot.stamp.elapsedMSec() << " msec");
|
||||
}
|
||||
|
||||
@@ -642,7 +643,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
if (slot.isNewDirectory) {
|
||||
int rc = path.create_dir( 0755 );
|
||||
if (rc) {
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Cannot create directory '" << path << "', return code = " << rc );
|
||||
fail(slot.currentItem);
|
||||
return;
|
||||
@@ -661,7 +662,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
slot.nextWarnTimeout = 20000;
|
||||
slot.stamp.stamp();
|
||||
slot.busy = true;
|
||||
SG_LOG(SG_TERRAIN, SG_INFO, "sync of " << slot.repository->baseUrl() << " started, queue size is " << slot.queue.size());
|
||||
SG_LOG(SG_TERRASYNC, SG_INFO, "sync of " << slot.repository->baseUrl() << " started, queue size is " << slot.queue.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,7 +683,7 @@ void SGTerraSync::SvnThread::runInternal()
|
||||
SyncItem::Status cacheStatus = isPathCached(next);
|
||||
if (cacheStatus != SyncItem::Invalid) {
|
||||
_cache_hits++;
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "\nTerraSync Cache hit for: '" << next._dir << "'");
|
||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "\nTerraSync Cache hit for: '" << next._dir << "'");
|
||||
next._status = cacheStatus;
|
||||
_freshTiles.push_back(next);
|
||||
_is_dirty = true;
|
||||
@@ -739,8 +740,8 @@ void SGTerraSync::SvnThread::fail(SyncItem failedItem)
|
||||
_fail_count++;
|
||||
failedItem._status = SyncItem::Failed;
|
||||
_freshTiles.push_back(failedItem);
|
||||
SG_LOG(SG_TERRAIN,SG_INFO,
|
||||
"Faield to sync'" << failedItem._dir << "'");
|
||||
SG_LOG(SG_TERRASYNC,SG_INFO,
|
||||
"Failed to sync'" << failedItem._dir << "'");
|
||||
_completedTiles[ failedItem._dir ] = now + UpdateInterval::FailedAttempt;
|
||||
_is_dirty = true;
|
||||
}
|
||||
@@ -765,7 +766,7 @@ void SGTerraSync::SvnThread::updated(SyncItem item, bool isNewDirectory)
|
||||
time_t now = time(0);
|
||||
_consecutive_errors = 0;
|
||||
_success_count++;
|
||||
SG_LOG(SG_TERRAIN,SG_INFO,
|
||||
SG_LOG(SG_TERRASYNC,SG_INFO,
|
||||
"Successfully synchronized directory '" << item._dir << "'");
|
||||
|
||||
item._status = SyncItem::Updated;
|
||||
@@ -791,7 +792,7 @@ void SGTerraSync::SvnThread::initCompletedTilesPersistentCache()
|
||||
try {
|
||||
readProperties(_persistentCachePath.str(), cacheRoot);
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_TERRAIN, SG_INFO, "corrupted persistent cache, discarding");
|
||||
SG_LOG(SG_TERRASYNC, SG_INFO, "corrupted persistent cache, discarding");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -852,7 +853,7 @@ SGTerraSync::SGTerraSync() :
|
||||
_inited(false)
|
||||
{
|
||||
_svnThread = new SvnThread();
|
||||
_log = new BufferedLogCallback(SG_TERRAIN, SG_INFO);
|
||||
_log = new BufferedLogCallback(SG_TERRASYNC, SG_INFO);
|
||||
_log->truncateAt(255);
|
||||
|
||||
sglog().addCallback(_log);
|
||||
@@ -977,13 +978,13 @@ void SGTerraSync::update(double)
|
||||
{
|
||||
if (_svnThread->_stalled)
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Automatic scenery download/synchronization stalled. Too many errors.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// not really an alert - just always show this message
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
SG_LOG(SG_TERRASYNC,SG_ALERT,
|
||||
"Automatic scenery download/synchronization has stopped.");
|
||||
}
|
||||
_stalledNode->setBoolValue(_svnThread->_stalled);
|
||||
@@ -1085,4 +1086,4 @@ bool SGTerraSync::isDataDirPending(const std::string& dataDir) const
|
||||
void SGTerraSync::reposition()
|
||||
{
|
||||
// stub, remove
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,4 @@
|
||||
|
||||
#cmakedefine SYSTEM_EXPAT
|
||||
#cmakedefine ENABLE_SOUND
|
||||
#cmakedefine ENABLE_CURL
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <stdlib.h> // rand(), free()
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
@@ -78,8 +79,12 @@ SGSoundSample::SGSoundSample() :
|
||||
_playing(false),
|
||||
_static_changed(true),
|
||||
_out_of_range(false),
|
||||
_is_file(false)
|
||||
_is_file(false),
|
||||
_use_pos_props(false)
|
||||
{
|
||||
_pos_prop[0] = 0;
|
||||
_pos_prop[1] = 0;
|
||||
_pos_prop[2] = 0;
|
||||
}
|
||||
|
||||
// constructor
|
||||
@@ -114,10 +119,14 @@ SGSoundSample::SGSoundSample(const char *file, const SGPath& currentDir) :
|
||||
_playing(false),
|
||||
_static_changed(true),
|
||||
_out_of_range(false),
|
||||
_is_file(true)
|
||||
_is_file(true),
|
||||
_use_pos_props(false)
|
||||
{
|
||||
SGPath p = simgear::ResourceManager::instance()->findPath(file, currentDir);
|
||||
_refname = p.str();
|
||||
_pos_prop[0] = 0;
|
||||
_pos_prop[1] = 0;
|
||||
_pos_prop[2] = 0;
|
||||
}
|
||||
|
||||
// constructor
|
||||
@@ -152,10 +161,14 @@ SGSoundSample::SGSoundSample( const unsigned char** data,
|
||||
_playing(false),
|
||||
_static_changed(true),
|
||||
_out_of_range(false),
|
||||
_is_file(false)
|
||||
_is_file(false),
|
||||
_use_pos_props(false)
|
||||
{
|
||||
SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" );
|
||||
_data = (unsigned char*)*data; *data = NULL;
|
||||
_pos_prop[0] = 0;
|
||||
_pos_prop[1] = 0;
|
||||
_pos_prop[2] = 0;
|
||||
}
|
||||
|
||||
// constructor
|
||||
@@ -189,10 +202,14 @@ SGSoundSample::SGSoundSample( void** data, int len, int freq, int format ) :
|
||||
_playing(false),
|
||||
_static_changed(true),
|
||||
_out_of_range(false),
|
||||
_is_file(false)
|
||||
_is_file(false),
|
||||
_use_pos_props(false)
|
||||
{
|
||||
SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" );
|
||||
_data = (unsigned char*)*data; *data = NULL;
|
||||
_pos_prop[0] = 0;
|
||||
_pos_prop[1] = 0;
|
||||
_pos_prop[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,9 +220,16 @@ SGSoundSample::~SGSoundSample() {
|
||||
|
||||
void SGSoundSample::update_pos_and_orientation() {
|
||||
|
||||
_absolute_pos = _base_pos;
|
||||
if (_relative_pos[0] || _relative_pos[1] || _relative_pos[2] ) {
|
||||
_absolute_pos += _rotation.rotate( _relative_pos );
|
||||
if (_use_pos_props) {
|
||||
if (_pos_prop[0]) _absolute_pos[0] = _pos_prop[0]->getDoubleValue();
|
||||
if (_pos_prop[1]) _absolute_pos[1] = _pos_prop[1]->getDoubleValue();
|
||||
if (_pos_prop[2]) _absolute_pos[2] = _pos_prop[2]->getDoubleValue();
|
||||
}
|
||||
else {
|
||||
_absolute_pos = _base_pos;
|
||||
if (_relative_pos[0] || _relative_pos[1] || _relative_pos[2] ) {
|
||||
_absolute_pos += _rotation.rotate( _relative_pos );
|
||||
}
|
||||
}
|
||||
|
||||
_orivec = SGVec3f::zeros();
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
class SGPath;
|
||||
|
||||
@@ -334,7 +335,13 @@ public:
|
||||
* @param pos position in Cartesian coordinates
|
||||
*/
|
||||
inline void set_position( const SGVec3d& pos ) {
|
||||
_base_pos = pos; _changed = true;
|
||||
_base_pos = pos; _changed = true;
|
||||
}
|
||||
|
||||
inline void set_position_properties(SGPropertyNode_ptr pos[3]) {
|
||||
_pos_prop[0] = pos[0]; _pos_prop[1] = pos[1]; _pos_prop[2] = pos[2];
|
||||
if (pos[0] || pos[1] || pos[2]) _use_pos_props = true;
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -458,6 +465,7 @@ public:
|
||||
* @return Sample name
|
||||
*/
|
||||
inline std::string get_sample_name() const { return _refname; }
|
||||
inline void set_sample_name(const std::string& refname) { _refname = refname; }
|
||||
|
||||
inline virtual bool is_queue() const { return false; }
|
||||
|
||||
@@ -476,6 +484,7 @@ protected:
|
||||
private:
|
||||
|
||||
// Position of the source sound.
|
||||
SGPropertyNode_ptr _pos_prop[3]; // always absolute
|
||||
SGVec3d _absolute_pos; // absolute position
|
||||
SGVec3d _relative_pos; // position relative to the base position
|
||||
SGVec3d _direction; // orientation offset
|
||||
@@ -513,6 +522,7 @@ private:
|
||||
bool _static_changed;
|
||||
bool _out_of_range;
|
||||
bool _is_file;
|
||||
bool _use_pos_props;
|
||||
|
||||
std::string random_string();
|
||||
};
|
||||
|
||||
@@ -239,7 +239,6 @@ void SGSoundMgr::init()
|
||||
|
||||
if (_vendor == "Creative Labs Inc.") {
|
||||
_bad_doppler = true;
|
||||
|
||||
} else if (_vendor == "OpenAL Community" && _renderer == "OpenAL Soft") {
|
||||
_bad_doppler = true;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory> // for std::auto_ptr
|
||||
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
|
||||
void init();
|
||||
void update(double dt);
|
||||
|
||||
|
||||
void suspend();
|
||||
void resume();
|
||||
void stop();
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
*/
|
||||
bool add( SGSampleGroup *sgrp, const std::string& refname );
|
||||
|
||||
/**
|
||||
/**
|
||||
* Remove a sample group from the sound manager.
|
||||
* @param refname Reference name of the sample group to remove
|
||||
* @return true if successful, false otherwise
|
||||
@@ -268,11 +268,12 @@ public:
|
||||
const std::string& get_vendor() { return _vendor; }
|
||||
const std::string& get_renderer() { return _renderer; }
|
||||
|
||||
static const char* subsystemName() { return "sound"; };
|
||||
private:
|
||||
class SoundManagerPrivate;
|
||||
/// private implementation object
|
||||
std::auto_ptr<SoundManagerPrivate> d;
|
||||
|
||||
|
||||
bool _active;
|
||||
bool _changed;
|
||||
float _volume;
|
||||
@@ -298,5 +299,3 @@ private:
|
||||
|
||||
|
||||
#endif // _SG_SOUNDMGR_OPENAL_HXX
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
@@ -249,10 +250,27 @@ SGXmlSound::init( SGPropertyNode *root,
|
||||
//
|
||||
SGVec3f offset_pos = SGVec3f::zeros();
|
||||
SGPropertyNode_ptr prop = node->getChild("position");
|
||||
SGPropertyNode_ptr pos_prop[3];
|
||||
if ( prop != NULL ) {
|
||||
offset_pos[0] = -prop->getDoubleValue("x", 0.0);
|
||||
offset_pos[1] = -prop->getDoubleValue("y", 0.0);
|
||||
offset_pos[2] = -prop->getDoubleValue("z", 0.0);
|
||||
|
||||
pos_prop[0] = prop->getChild("x");
|
||||
if (pos_prop[0]) pos_prop[0] = pos_prop[0]->getNode("property");
|
||||
if (pos_prop[0]) {
|
||||
pos_prop[0] = root->getNode(pos_prop[0]->getStringValue(), true);
|
||||
}
|
||||
pos_prop[1] = prop->getChild("y");
|
||||
if (pos_prop[1]) pos_prop[1] = pos_prop[1]->getNode("property");
|
||||
if (pos_prop[1]) {
|
||||
pos_prop[1] = root->getNode(pos_prop[1]->getStringValue(), true);
|
||||
}
|
||||
pos_prop[2] = prop->getChild("z");
|
||||
if (pos_prop[2]) pos_prop[2] = pos_prop[1]->getNode("property");
|
||||
if (pos_prop[2]) {
|
||||
pos_prop[2] = root->getNode(pos_prop[2]->getStringValue(), true);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -284,9 +302,11 @@ SGXmlSound::init( SGPropertyNode *root,
|
||||
_sample = new SGSoundSample(soundFileStr.c_str(), path);
|
||||
if (!_sample->file_path().exists()) {
|
||||
throw sg_io_exception("XML sound: couldn't find file: '" + soundFileStr + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
_sample->set_relative_position( offset_pos );
|
||||
_sample->set_position_properties( pos_prop );
|
||||
_sample->set_direction( dir );
|
||||
_sample->set_audio_cone( inner, outer, outer_gain );
|
||||
_sample->set_reference_dist( reference_dist );
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2005-2006 Mathias Froehlich
|
||||
* Copyright (C) 2005-2006 Mathias Froehlich
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
|
||||
@@ -234,6 +234,7 @@ SGSubsystemGroup::update (double delta_time_sec)
|
||||
if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
|
||||
double localDelta = delta_time_sec + _updateTimeRemainder;
|
||||
loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
|
||||
loopCount = std::max(0, loopCount);
|
||||
_updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
|
||||
delta_time_sec = _fixedUpdateTime;
|
||||
}
|
||||
@@ -301,8 +302,6 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
|
||||
double min_step_sec)
|
||||
{
|
||||
Member * member = get_member(name, true);
|
||||
if (member->subsystem != 0)
|
||||
delete member->subsystem;
|
||||
member->name = name;
|
||||
member->subsystem = subsystem;
|
||||
member->min_step_sec = min_step_sec;
|
||||
@@ -430,11 +429,11 @@ SGSubsystemGroup::Member::update (double delta_time_sec)
|
||||
|
||||
|
||||
SGSubsystemMgr::SGSubsystemMgr () :
|
||||
_groups(MAX_GROUPS),
|
||||
_initPosition(0)
|
||||
{
|
||||
for (int i = 0; i < MAX_GROUPS; i++) {
|
||||
_groups[i] = new SGSubsystemGroup;
|
||||
}
|
||||
for (int i = 0; i < MAX_GROUPS; i++)
|
||||
_groups[i].reset(new SGSubsystemGroup);
|
||||
}
|
||||
|
||||
SGSubsystemMgr::~SGSubsystemMgr ()
|
||||
@@ -442,10 +441,7 @@ SGSubsystemMgr::~SGSubsystemMgr ()
|
||||
// ensure get_subsystem returns NULL from now onwards,
|
||||
// before the SGSubsystemGroup destructors are run
|
||||
_subsystem_map.clear();
|
||||
|
||||
for (int i = 0; i < MAX_GROUPS; i++) {
|
||||
delete _groups[i];
|
||||
}
|
||||
_groups.clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -39,7 +39,7 @@ private:
|
||||
std::string eventName;
|
||||
SGTimeStamp time;
|
||||
|
||||
public:
|
||||
public:
|
||||
TimingInfo(const std::string& name, const SGTimeStamp &t) :
|
||||
eventName(name), time(t)
|
||||
{ }
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
INIT_DONE, ///< subsystem is fully initialised
|
||||
INIT_CONTINUE ///< init should be called again
|
||||
} InitStatus;
|
||||
|
||||
|
||||
virtual InitStatus incrementalInit ();
|
||||
|
||||
/**
|
||||
@@ -186,7 +186,7 @@ public:
|
||||
* </p>
|
||||
*/
|
||||
virtual void shutdown ();
|
||||
|
||||
|
||||
/**
|
||||
* Acquire the subsystem's property bindings.
|
||||
*
|
||||
@@ -267,7 +267,7 @@ public:
|
||||
void reportTiming(void);
|
||||
|
||||
/**
|
||||
* Place time stamps at strategic points in the execution of subsystems
|
||||
* Place time stamps at strategic points in the execution of subsystems
|
||||
* update() member functions. Predominantly for debugging purposes.
|
||||
*/
|
||||
void stamp(const std::string& name);
|
||||
@@ -324,12 +324,12 @@ public:
|
||||
*
|
||||
*/
|
||||
void set_fixed_update_time(double fixed_dt);
|
||||
|
||||
|
||||
/**
|
||||
* retrive list of member subsystem names
|
||||
*/
|
||||
*/
|
||||
string_list member_names() const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
class Member;
|
||||
@@ -337,14 +337,16 @@ private:
|
||||
|
||||
typedef std::vector<Member *> MemberVec;
|
||||
MemberVec _members;
|
||||
|
||||
|
||||
double _fixedUpdateTime;
|
||||
double _updateTimeRemainder;
|
||||
|
||||
|
||||
/// index of the member we are currently init-ing
|
||||
unsigned int _initPosition;
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<SGSubsystemGroup> SGSubsystemGroupRef;
|
||||
|
||||
/**
|
||||
* Manage subsystems for FlightGear.
|
||||
*
|
||||
@@ -396,7 +398,7 @@ public:
|
||||
|
||||
virtual void add (const char * name,
|
||||
SGSubsystem * subsystem,
|
||||
GroupType group = GENERAL,
|
||||
GroupType group = GENERAL,
|
||||
double min_time_sec = 0);
|
||||
|
||||
/**
|
||||
@@ -412,10 +414,16 @@ public:
|
||||
void reportTiming();
|
||||
void setReportTimingCb(void* userData,SGSubsystemTimingCb cb) {reportTimingCb = cb;reportTimingUserData = userData;}
|
||||
|
||||
template<class T>
|
||||
T* get_subsystem() const
|
||||
{
|
||||
return dynamic_cast<T*>(get_subsystem(T::subsystemName()));
|
||||
}
|
||||
|
||||
private:
|
||||
SGSubsystemGroup* _groups[MAX_GROUPS];
|
||||
std::vector<SGSubsystemGroupRef> _groups;
|
||||
unsigned int _initPosition;
|
||||
|
||||
|
||||
// non-owning reference
|
||||
typedef std::map<std::string, SGSubsystem*> SubsystemDict;
|
||||
SubsystemDict _subsystem_map;
|
||||
|
||||
@@ -170,13 +170,6 @@ static double sidereal_course( time_t cur_time, const struct tm *gmt, double lng
|
||||
return lstTmp;
|
||||
}
|
||||
|
||||
/** Deprecated method. To be removed after the next release... */
|
||||
void SGTime::update( double lon_rad, double lat_rad, time_t ct, long int warp )
|
||||
{
|
||||
const SGGeod& location = SGGeod::fromRad(lon_rad, lat_rad);
|
||||
update(location, ct, warp);
|
||||
}
|
||||
|
||||
// Update the time related variables
|
||||
void SGTime::update( const SGGeod& location, time_t ct, long int warp )
|
||||
{
|
||||
|
||||
@@ -151,9 +151,6 @@ public:
|
||||
*/
|
||||
void update( const SGGeod& location, time_t ct, long int warp );
|
||||
|
||||
/** Deprecated method. To be removed after the next release... */
|
||||
void update( double lon_rad, double lat_rad, time_t ct, long int warp ) DEPRECATED;
|
||||
|
||||
/**
|
||||
* Given lon/lat, update timezone information and local_offset
|
||||
* The updateLocal() method is intended to be called less
|
||||
|
||||
Reference in New Issue
Block a user