Initial work on package management.

Basic library infrastructure, catalog download/refresh, and package install,
uninstall and update. Disabled at cmake time by default, and not yet hooked
into FlightGear.
This commit is contained in:
James Turner 2013-02-13 13:32:19 +00:00
parent 3c8cfe9b76
commit a530712491
18 changed files with 1810 additions and 2 deletions

View File

@ -112,6 +112,7 @@ option(ENABLE_LIBSVN "Set to ON to build SimGear with libsvnclient support" O
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_PACKAGE "Set to ON to build package-management support" OFF)
if (MSVC)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_SOURCE_DIR} PATH)
@ -223,6 +224,13 @@ else()
add_definitions(-DHAVE_EXPAT_CONFIG_H)
endif(SYSTEM_EXPAT)
if (ENABLE_PACKAGE)
message(STATUS "package management: ENABLED: libArchive is needed")
find_package(LibArchive REQUIRED)
else()
message(STATUS "package management: DISABLED")
endif(ENABLE_PACKAGE)
check_include_file(inttypes.h HAVE_INTTYPES_H)
check_include_file(sys/time.h HAVE_SYS_TIME_H)
check_include_file(sys/timeb.h HAVE_SYS_TIMEB_H)
@ -335,8 +343,11 @@ include_directories(${PROJECT_BINARY_DIR}/simgear)
include_directories(${PROJECT_BINARY_DIR}/simgear/xml)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR}
${OPENAL_INCLUDE_DIR} )
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${OPENAL_INCLUDE_DIR}
${LibArchive_INCLUDE_DIRS}
)
add_definitions(-DHAVE_CONFIG_H)

View File

@ -0,0 +1,77 @@
# - Find libarchive library and headers
# The module defines the following variables:
#
# LibArchive_FOUND - true if libarchive was found
# LibArchive_INCLUDE_DIRS - include search path
# LibArchive_LIBRARIES - libraries to link
# LibArchive_VERSION - libarchive 3-component version number
#=============================================================================
# Copyright 2010 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.)
find_path(LibArchive_INCLUDE_DIR
NAMES archive.h
PATHS
${CMAKE_INSTALL_PREFIX}
${ADDITIONAL_LIBRARY_PATHS}
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\LibArchive;InstallPath]/include"
)
# NO_DEFAULT_PATH is important on Mac - the libarchive in /usr/lib
# is too old, and there's no matching headers :(
find_library(LibArchive_LIBRARY
if(APPLE)
NO_DEFAULT_PATH
endif(APPLE)
NAMES archive libarchive
PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64
PATHS
${CMAKE_INSTALL_PREFIX}
${ADDITIONAL_LIBRARY_PATHS}
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\LibArchive;InstallPath]/lib"
)
mark_as_advanced(LibArchive_INCLUDE_DIR LibArchive_LIBRARY)
# Extract the version number from the header.
if(LibArchive_INCLUDE_DIR AND EXISTS "${LibArchive_INCLUDE_DIR}/archive.h")
# The version string appears in one of two known formats in the header:
# #define ARCHIVE_LIBRARY_VERSION "libarchive 2.4.12"
# #define ARCHIVE_VERSION_STRING "libarchive 2.8.4"
# Match either format.
set(_LibArchive_VERSION_REGEX "^#define[ \t]+ARCHIVE[_A-Z]+VERSION[_A-Z]*[ \t]+\"libarchive +([0-9]+)\\.([0-9]+)\\.([0-9]+)[^\"]*\".*$")
file(STRINGS "${LibArchive_INCLUDE_DIR}/archive.h" _LibArchive_VERSION_STRING LIMIT_COUNT 1 REGEX "${_LibArchive_VERSION_REGEX}")
if(_LibArchive_VERSION_STRING)
string(REGEX REPLACE "${_LibArchive_VERSION_REGEX}" "\\1.\\2.\\3" LibArchive_VERSION "${_LibArchive_VERSION_STRING}")
endif()
unset(_LibArchive_VERSION_REGEX)
unset(_LibArchive_VERSION_STRING)
endif()
# Handle the QUIETLY and REQUIRED arguments and set LIBARCHIVE_FOUND
# to TRUE if all listed variables are TRUE.
# (Use ${CMAKE_ROOT}/Modules instead of ${CMAKE_CURRENT_LIST_DIR} because CMake
# itself includes this FindLibArchive when built with an older CMake that does
# not provide it. The older CMake also does not have CMAKE_CURRENT_LIST_DIR.)
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
find_package_handle_standard_args(LibArchive
REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
VERSION_VAR LibArchive_VERSION
)
set(LibArchive_FOUND ${LIBARCHIVE_FOUND})
unset(LIBARCHIVE_FOUND)
if(LibArchive_FOUND)
set(LibArchive_INCLUDE_DIRS ${LibArchive_INCLUDE_DIR})
set(LibArchive_LIBRARIES ${LibArchive_LIBRARY})
endif()

View File

@ -24,6 +24,10 @@ foreach( mylibfolder
endforeach( mylibfolder )
if (ENABLE_PACKAGE)
add_subdirectory(package)
endif(ENABLE_PACKAGE)
if(NOT SIMGEAR_HEADLESS)
add_subdirectory(canvas)
add_subdirectory(environment)
@ -63,6 +67,7 @@ if(SIMGEAR_SHARED)
set_property(TARGET SimGearCore PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
target_link_libraries(SimGearCore ${ZLIB_LIBRARY} ${RT_LIBRARY}
${LibArchive_LIBRARIES}
${EXPAT_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT})

View File

@ -455,6 +455,11 @@ public:
{
return !queuedRequests.empty() && (sentRequests.size() < MAX_INFLIGHT_REQUESTS);
}
bool isActive() const
{
return !queuedRequests.empty() || !sentRequests.empty();
}
private:
bool connectToHost()
{
@ -733,6 +738,16 @@ void Client::setProxy(const string& proxy, int port, const string& auth)
_proxyAuth = auth;
}
bool Client::hasActiveRequests() const
{
ConnectionDict::const_iterator it = _connections.begin();
for (; it != _connections.end(); ++it) {
if (it->second->isActive()) return true;
}
return false;
}
} // of namespace HTTP
} // of namespace simgear

View File

@ -33,6 +33,12 @@ public:
const std::string& proxyAuth() const
{ return _proxyAuth; }
/**
* predicate, check if at least one connection is active, with at
* least one request active or queued.
*/
bool hasActiveRequests() const;
private:
void requestFinished(Connection* con);

View File

@ -0,0 +1,41 @@
include (SimGearComponent)
set(HEADERS
Catalog.hxx
Package.hxx
Install.hxx
Root.hxx
Delegate.hxx
)
set(SOURCES
Catalog.cxx
Package.cxx
Install.cxx
Root.cxx
md5.c
)
simgear_component(package package "${SOURCES}" "${HEADERS}")
if (SIMGEAR_SHARED)
set(APP_LIBS SimGearCore)
else()
set(APP_LIBS
${LibArchive_LIBRARIES}
SimGearCore
${CMAKE_THREAD_LIBS_INIT}
${WINSOCK_LIBRARY}
${ZLIB_LIBRARY}
${RT_LIBRARY}
)
endif()
add_executable(sg_pkgutil pkgutil.cxx)
target_link_libraries(sg_pkgutil ${APP_LIBS})
if(ENABLE_TESTS)
endif(ENABLE_TESTS)

267
simgear/package/Catalog.cxx Normal file
View File

@ -0,0 +1,267 @@
#include <simgear/package/Catalog.hxx>
#include <boost/foreach.hpp>
#include <fstream>
#include <cstring>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/io/HTTPRequest.hxx>
#include <simgear/io/HTTPClient.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/package/Package.hxx>
#include <simgear/package/Root.hxx>
#include <simgear/package/Install.hxx>
namespace simgear {
namespace pkg {
CatalogList static_catalogs;
//////////////////////////////////////////////////////////////////////////////
class Catalog::Downloader : public HTTP::Request
{
public:
Downloader(Catalog* aOwner, const std::string& aUrl) :
HTTP::Request(aUrl),
m_owner(aOwner)
{
}
protected:
virtual void responseHeadersComplete()
{
}
virtual void gotBodyData(const char* s, int n)
{
m_buffer += std::string(s, n);
}
virtual void responseComplete()
{
if (responseCode() != 200) {
SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
m_owner->refreshComplete(false);
return;
}
SGPropertyNode* props = new SGPropertyNode;
try {
readProperties(m_buffer.data(), m_buffer.size(), props);
m_owner->parseProps(props);
} catch (sg_exception& e) {
SG_LOG(SG_GENERAL, SG_ALERT, "catalog parse failure:" << m_owner->url());
m_owner->refreshComplete(false);
return;
}
// cache the catalog data, now we have a valid install root
Dir d(m_owner->installRoot());
SGPath p = d.file("catalog.xml");
std::ofstream f(p.c_str(), std::ios::out | std::ios::trunc);
f.write(m_buffer.data(), m_buffer.size());
f.close();
time(&m_owner->m_retrievedTime);
m_owner->writeTimestamp();
m_owner->refreshComplete(true);
}
private:
Catalog* m_owner;
std::string m_buffer;
};
//////////////////////////////////////////////////////////////////////////////
CatalogList Catalog::allCatalogs()
{
return static_catalogs;
}
Catalog::Catalog(Root *aRoot) :
m_root(aRoot),
m_retrievedTime(0)
{
static_catalogs.push_back(this);
}
Catalog::~Catalog()
{
CatalogList::iterator it = std::find(static_catalogs.begin(), static_catalogs.end(), this);
static_catalogs.erase(it);
}
Catalog* Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
{
Catalog* c = new Catalog(aRoot);
Downloader* dl = new Downloader(c, aUrl);
aRoot->getHTTPClient()->makeRequest(dl);
return c;
}
Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
{
SGPath xml = aPath;
xml.append("catalog.xml");
if (!xml.exists()) {
return NULL;
}
SGPropertyNode_ptr props;
try {
props = new SGPropertyNode;
readProperties(xml.str(), props);
} catch (sg_exception& e) {
return NULL;
}
Catalog* c = new Catalog(aRoot);
c->m_installRoot = aPath;
c->parseProps(props);
c->parseTimestamp();
return c;
}
PackageList
Catalog::packagesMatching(const SGPropertyNode* aFilter) const
{
PackageList r;
BOOST_FOREACH(Package* p, m_packages) {
if (p->matches(aFilter)) {
r.push_back(p);
}
}
return r;
}
PackageList
Catalog::packagesNeedingUpdate() const
{
PackageList r;
BOOST_FOREACH(Package* p, m_packages) {
if (!p->isInstalled()) {
continue;
}
if (p->install()->hasUpdate()) {
r.push_back(p);
}
}
return r;
}
void Catalog::refresh()
{
Downloader* dl = new Downloader(this, url());
m_root->getHTTPClient()->makeRequest(dl);
m_root->catalogRefreshBegin(this);
}
void Catalog::parseProps(const SGPropertyNode* aProps)
{
// copy everything except package children?
m_props = new SGPropertyNode;
int nChildren = aProps->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode* pkgProps = aProps->getChild(i);
if (strcmp(pkgProps->getName(), "package") == 0) {
Package* p = new Package(pkgProps, this);
m_packages.push_back(p);
} else {
SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true);
copyProperties(pkgProps, c);
}
} // of children iteration
if (m_installRoot.isNull()) {
m_installRoot = m_root->path();
m_installRoot.append(id());
Dir d(m_installRoot);
d.create(0755);
}
}
Package* Catalog::getPackageById(const std::string& aId) const
{
BOOST_FOREACH(Package* p, m_packages) {
if (p->id() == aId) {
return p;
}
}
return NULL; // not found
}
std::string Catalog::id() const
{
return m_props->getStringValue("id");
}
std::string Catalog::url() const
{
return m_props->getStringValue("url");
}
std::string Catalog::description() const
{
return getLocalisedString(m_props, "description");
}
void Catalog::parseTimestamp()
{
SGPath timestampFile = m_installRoot;
timestampFile.append(".timestamp");
std::ifstream f(timestampFile.c_str(), std::ios::in);
f >> m_retrievedTime;
}
void Catalog::writeTimestamp()
{
SGPath timestampFile = m_installRoot;
timestampFile.append(".timestamp");
std::ofstream f(timestampFile.c_str(), std::ios::out | std::ios::trunc);
f << m_retrievedTime << std::endl;
}
int Catalog::ageInSeconds() const
{
time_t now;
time(&now);
return ::difftime(now, m_retrievedTime);
}
std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
{
if (aRoot->hasChild(m_root->getLocale())) {
const SGPropertyNode* localeRoot = aRoot->getChild(m_root->getLocale().c_str());
if (localeRoot->hasChild(aName)) {
return localeRoot->getStringValue(aName);
}
}
return aRoot->getStringValue(aName);
}
void Catalog::refreshComplete(bool aSuccess)
{
m_root->catalogRefreshComplete(this, aSuccess);
}
} // of namespace pkg
} // of namespace simgear

View File

@ -0,0 +1,95 @@
#ifndef SG_PACKAGE_CATALOG_HXX
#define SG_PACKAGE_CATALOG_HXX
#include <vector>
#include <ctime>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
namespace simgear
{
namespace HTTP { class Client; }
namespace pkg
{
// forward decls
class Package;
class Catalog;
class Root;
typedef std::vector<Package*> PackageList;
typedef std::vector<Catalog*> CatalogList;
class Catalog
{
public:
virtual ~Catalog();
static Catalog* createFromUrl(Root* aRoot, const std::string& aUrl);
static Catalog* createFromPath(Root* aRoot, const SGPath& aPath);
static CatalogList allCatalogs();
Root* root() const
{ return m_root;};
/**
* perform a refresh of the catalog contents
*/
void refresh();
/**
* retrieve packages in this catalog matching a filter.
* filter consists of required / minimum values, AND-ed together.
*/
PackageList packagesMatching(const SGPropertyNode* aFilter) const;
/**
* retrieve all the packages in the catalog which are installed
* and have a pendig update
*/
PackageList packagesNeedingUpdate() const;
SGPath installRoot() const
{ return m_installRoot; }
std::string id() const;
std::string url() const;
std::string description() const;
Package* getPackageById(const std::string& aId) const;
int ageInSeconds() const;
private:
Catalog(Root* aRoot);
class Downloader;
friend class Downloader;
void parseProps(const SGPropertyNode* aProps);
void refreshComplete(bool aSuccess);
void parseTimestamp();
void writeTimestamp();
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
Root* m_root;
SGPropertyNode_ptr m_props;
SGPath m_installRoot;
PackageList m_packages;
time_t m_retrievedTime;
};
} // of namespace pkg
} // of namespace simgear
#endif // of SG_PACKAGE_CATALOG_HXX

View File

@ -0,0 +1,41 @@
#ifndef SG_PACKAGE_DELEGATE_HXX
#define SG_PACKAGE_DELEGATE_HXX
namespace simgear
{
namespace pkg
{
class Install;
class Delegate
{
public:
virtual ~Delegate() { }
virtual void refreshComplete() = 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;
typedef enum {
FAIL_UNKNOWN = 0,
FAIL_CHECKSUM,
FAIL_DOWNLOAD,
FAIL_EXTRACT,
FAIL_FILESYSTEM
} FailureCode;
virtual void failedInstall(Install* aInstall, FailureCode aReason) = 0;
};
} // of namespace pkg
} // of namespace simgear
#endif // of SG_PACKAGE_DELEGATE_HXX

218
simgear/package/Install.cxx Normal file
View File

@ -0,0 +1,218 @@
#include <simgear/package/Install.hxx>
#include <boost/foreach.hpp>
#include <fstream>
// libarchive support
#include <archive.h>
#include <archive_entry.h>
#include <simgear/package/md5.h>
#include <simgear/structure/exception.hxx>
#include <simgear/package/Catalog.hxx>
#include <simgear/package/Package.hxx>
#include <simgear/package/Root.hxx>
#include <simgear/io/HTTPRequest.hxx>
#include <simgear/io/HTTPClient.hxx>
#include <simgear/misc/sg_dir.hxx>
namespace simgear {
namespace pkg {
class Install::PackageArchiveDownloader : public HTTP::Request
{
public:
PackageArchiveDownloader(Install* aOwner) :
HTTP::Request("" /* dummy URL */),
m_owner(aOwner)
{
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
}
protected:
virtual std::string url() const
{
return m_urls.front();
}
virtual void responseHeadersComplete()
{
std::cout << "starting download of " << m_owner->package()->id() << " from "
<< url() << std::endl;
Dir d(m_extractPath);
d.create(0755);
memset(&m_md5, 0, sizeof(MD5_CTX));
MD5Init(&m_md5);
}
virtual void gotBodyData(const char* s, int n)
{
m_buffer += std::string(s, n);
MD5Update(&m_md5, (unsigned char*) s, n);
std::cout << "got " << m_buffer.size() << " bytes" << std::endl;
}
virtual void responseComplete()
{
if (responseCode() != 200) {
SG_LOG(SG_GENERAL, SG_ALERT, "download failure");
doFailure();
return;
}
std::cout << "content lenth:" << responseLength() << std::endl;
std::cout << m_buffer.size() << " total received" << std::endl;
MD5Final(&m_md5);
// convert final sum to hex
const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
std::stringstream hexMd5;
for (int i=0; i<16;++i) {
hexMd5 << hexChar[m_md5.digest[i] >> 4];
hexMd5 << hexChar[m_md5.digest[i] & 0x0f];
}
if (hexMd5.str() != m_owner->package()->md5()) {
SG_LOG(SG_GENERAL, SG_ALERT, "md5 verification failed:\n"
<< "\t" << hexMd5.str() << "\n\t"
<< m_owner->package()->md5() << "\n\t"
<< "downloading from:" << url());
doFailure();
return;
} else {
std::cout << "MD5 checksum is ok" << std::endl;
}
struct archive* a = archive_read_new();
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
int result = archive_read_open_memory(a, (void*) m_buffer.data(), m_buffer.size());
if (result != ARCHIVE_OK) {
doFailure();
return;
}
struct archive_entry* entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
SGPath finalPath(m_extractPath);
finalPath.append(archive_entry_pathname(entry));
// std::cout << "writing:" << finalPath << std::endl;
archive_entry_set_pathname(entry, finalPath.c_str());
archive_read_extract(a, entry, 0);
}
archive_read_free(a);
if (m_owner->path().exists()) {
std::cout << "removing existing path" << std::endl;
Dir destDir(m_owner->path());
destDir.remove(true /* recursive */);
}
std::cout << "renaming to " << m_owner->path() << std::endl;
m_extractPath.append(m_owner->package()->id());
m_extractPath.rename(m_owner->path());
m_owner->m_revision = m_owner->package()->revision();
m_owner->writeRevisionFile();
}
private:
void doFailure()
{
Dir dir(m_extractPath);
dir.remove(true /* recursive */);
if (m_urls.size() == 1) {
return;
}
m_urls.erase(m_urls.begin()); // pop first URL
}
Install* m_owner;
string_list m_urls;
MD5_CTX m_md5;
std::string m_buffer;
SGPath m_extractPath;
};
////////////////////////////////////////////////////////////////////
Install::Install(Package* aPkg, const SGPath& aPath) :
m_package(aPkg),
m_path(aPath),
m_download(NULL)
{
parseRevision();
}
Install* Install::createFromPath(const SGPath& aPath, Catalog* aCat)
{
std::string id = aPath.file();
Package* pkg = aCat->getPackageById(id);
if (!pkg)
throw sg_exception("no package with id:" + id);
return new Install(pkg, aPath);
}
void Install::parseRevision()
{
SGPath revisionFile = m_path;
revisionFile.append(".revision");
if (!revisionFile.exists()) {
m_revision = 0;
return;
}
std::ifstream f(revisionFile.c_str(), std::ios::in);
f >> m_revision;
}
void Install::writeRevisionFile()
{
SGPath revisionFile = m_path;
revisionFile.append(".revision");
std::ofstream f(revisionFile.c_str(), std::ios::out | std::ios::trunc);
f << m_revision << std::endl;
}
bool Install::hasUpdate() const
{
return m_package->revision() > m_revision;
}
void Install::startUpdate()
{
if (m_download) {
return; // already active
}
m_download = new PackageArchiveDownloader(this);
m_package->catalog()->root()->getHTTPClient()->makeRequest(m_download);
}
void Install::uninstall()
{
Dir d(m_path);
d.remove(true);
delete this;
}
} // of namespace pkg
} // of namespace simgear

View File

@ -0,0 +1,72 @@
#ifndef SG_PACKAGE_INSTALL_HXX
#define SG_PACKAGE_INSTALL_HXX
#include <vector>
#include <simgear/misc/sg_path.hxx>
namespace simgear
{
namespace pkg
{
// forward decls
class Package;
class Catalog;
/**
*
*/
class Install
{
public:
/**
* create from a directory on disk, or fail.
*/
static Install* createFromPath(const SGPath& aPath, Catalog* aCat);
unsigned int revsion() const
{ return m_revision; }
Package* package() const
{ return m_package; }
SGPath path() const
{ return m_path; }
bool hasUpdate() const;
void startUpdate();
void uninstall();
// boost signals time?
// failure
// progress
// completed
private:
friend class Package;
class PackageArchiveDownloader;
friend class PackageArchiveDownloader;
Install(Package* aPkg, const SGPath& aPath);
void parseRevision();
void writeRevisionFile();
Package* m_package;
unsigned int m_revision; ///< revision on disk
SGPath m_path; ///< installation point on disk
PackageArchiveDownloader* m_download;
};
} // of namespace pkg
} // of namespace simgear
#endif // of SG_PACKAGE_CATALOG_HXX

126
simgear/package/Package.cxx Normal file
View File

@ -0,0 +1,126 @@
#include <simgear/package/Package.hxx>
#include <boost/foreach.hpp>
#include <simgear/debug/logstream.hxx>
#include <simgear/package/Catalog.hxx>
#include <simgear/package/Install.hxx>
#include <simgear/package/Root.hxx>
namespace simgear {
namespace pkg {
Package::Package(const SGPropertyNode* aProps, Catalog* aCatalog) :
m_catalog(aCatalog)
{
initWithProps(aProps);
}
void Package::initWithProps(const SGPropertyNode* aProps)
{
m_props = const_cast<SGPropertyNode*>(aProps);
// cache tag values
BOOST_FOREACH(const SGPropertyNode* c, aProps->getChildren("tag")) {
m_tags.insert(c->getStringValue());
}
}
bool Package::matches(const SGPropertyNode* aFilter) const
{
int nChildren = aFilter->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode* c = aFilter->getChild(i);
if (strutils::starts_with(c->getName(), "rating-")) {
int minRating = c->getIntValue();
std::string rname = c->getName() + 7;
int ourRating = m_props->getChild("rating")->getIntValue(rname, 0);
if (ourRating < minRating) {
return false;
}
}
if (strcmp(c->getName(), "tag") == 0) {
std::string tag(c->getStringValue());
if (m_tags.find(tag) == m_tags.end()) {
return false;
}
}
SG_LOG(SG_GENERAL, SG_WARN, "unknown filter term:" << c->getName());
} // of filter props iteration
return true;
}
bool Package::isInstalled() const
{
SGPath p(m_catalog->installRoot());
p.append("Aircraft");
p.append(id());
// anything to check for? look for a valid revision file?
return p.exists();
}
Install* Package::install()
{
SGPath p(m_catalog->installRoot());
p.append("Aircraft");
p.append(id());
if (p.exists()) {
return Install::createFromPath(p, m_catalog);
}
Install* ins = new Install(this, p);
m_catalog->root()->scheduleToUpdate(ins);
return ins;
}
std::string Package::id() const
{
return m_props->getStringValue("id");
}
std::string Package::md5() const
{
return m_props->getStringValue("md5");
}
unsigned int Package::revision() const
{
return m_props->getIntValue("revision");
}
string_list Package::downloadUrls() const
{
string_list r;
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("download")) {
r.push_back(dl->getStringValue());
}
return r;
}
std::string Package::getLocalisedProp(const std::string& aName) const
{
return getLocalisedString(m_props, aName.c_str());
}
std::string Package::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
{
std::string locale = m_catalog->root()->getLocale();
if (aRoot->hasChild(locale)) {
const SGPropertyNode* localeRoot = aRoot->getChild(locale.c_str());
if (localeRoot->hasChild(aName)) {
return localeRoot->getStringValue(aName);
}
}
return aRoot->getStringValue(aName);
}
} // of namespace pkg
} // of namespace simgear

View File

@ -0,0 +1,68 @@
#ifndef SG_PACKAGE_PACKAGE_HXX
#define SG_PACKAGE_PACKAGE_HXX
#include <set>
#include <vector>
#include <simgear/props/props.hxx>
#include <simgear/misc/strutils.hxx>
typedef std::set<std::string> string_set;
namespace simgear
{
namespace pkg
{
// forward decls
class Install;
class Catalog;
class Package
{
public:
/**
* get or create an install for the package
*/
Install* install();
bool isInstalled() const;
std::string id() const;
std::string md5() const;
std::string getLocalisedProp(const std::string& aName) const;
unsigned int revision() const;
Catalog* catalog() const
{ return m_catalog; }
bool matches(const SGPropertyNode* aFilter) const;
string_list downloadUrls() const;
private:
friend class Catalog;
Package(const SGPropertyNode* aProps, Catalog* aCatalog);
void initWithProps(const SGPropertyNode* aProps);
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
SGPropertyNode_ptr m_props;
string_set m_tags;
Catalog* m_catalog;
};
typedef std::vector<Package*> PackageList;
} // of namespace pkg
} // of namespace simgear
#endif // of SG_PACKAGE_PACKAGE_HXX

236
simgear/package/Root.cxx Normal file
View File

@ -0,0 +1,236 @@
#include <simgear/package/Root.hxx>
#include <boost/foreach.hpp>
#include <cstring>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/io/HTTPRequest.hxx>
#include <simgear/io/HTTPClient.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/package/Package.hxx>
#include <simgear/package/Install.hxx>
#include <simgear/package/Catalog.hxx>
namespace simgear {
namespace pkg {
void Root::setMaxAgeSeconds(int seconds)
{
m_maxAgeSeconds = seconds;
}
void Root::setHTTPClient(HTTP::Client* aHTTP)
{
m_http = aHTTP;
}
HTTP::Client* Root::getHTTPClient() const
{
return m_http;
}
Root::Root(const SGPath& aPath) :
m_path(aPath),
m_http(NULL),
m_maxAgeSeconds(60 * 60 * 24),
m_delegate(NULL)
{
if (getenv("LOCALE")) {
m_locale = getenv("LOCALE");
}
Dir d(aPath);
if (!d.exists()) {
d.create(0755);
return;
}
BOOST_FOREACH(SGPath c, d.children(Dir::TYPE_DIR)) {
Catalog* cat = Catalog::createFromPath(this, c);
if (cat) {
m_catalogs[cat->id()] = cat;
}
} // of child directories iteration
}
Root::~Root()
{
}
Catalog* Root::getCatalogById(const std::string& aId) const
{
CatalogDict::const_iterator it = m_catalogs.find(aId);
if (it == m_catalogs.end()) {
return NULL;
}
return it->second;
}
Package* Root::getPackageById(const std::string& aName) const
{
size_t lastDot = aName.rfind('.');
Package* pkg = NULL;
if (lastDot == -1) {
// naked package ID
CatalogDict::const_iterator it = m_catalogs.begin();
for (; it != m_catalogs.end(); ++it) {
pkg = it->second->getPackageById(aName);
if (pkg) {
return pkg;
}
}
return NULL;
}
std::string catalogId = aName.substr(0, lastDot);
std::string id = aName.substr(lastDot + 1);
Catalog* catalog = getCatalogById(catalogId);
if (!catalog) {
return NULL;
}
return catalog->getPackageById(id);
}
CatalogList Root::catalogs() const
{
CatalogList r;
CatalogDict::const_iterator it = m_catalogs.begin();
for (; it != m_catalogs.end(); ++it) {
r.push_back(it->second);
}
return r;
}
PackageList
Root::packagesMatching(const SGPropertyNode* aFilter) const
{
PackageList r;
CatalogDict::const_iterator it = m_catalogs.begin();
for (; it != m_catalogs.end(); ++it) {
PackageList r2(it->second->packagesMatching(aFilter));
r.insert(r.end(), r2.begin(), r2.end());
}
return r;
}
PackageList
Root::packagesNeedingUpdate() const
{
PackageList r;
CatalogDict::const_iterator it = m_catalogs.begin();
for (; it != m_catalogs.end(); ++it) {
PackageList r2(it->second->packagesNeedingUpdate());
r.insert(r.end(), r2.begin(), r2.end());
}
return r;
}
void Root::refresh(bool aForce)
{
CatalogDict::iterator it = m_catalogs.begin();
for (; it != m_catalogs.end(); ++it) {
if (aForce || (it->second->ageInSeconds() > m_maxAgeSeconds)) {
it->second->refresh();
}
}
}
void Root::setLocale(const std::string& aLocale)
{
m_locale = aLocale;
}
std::string Root::getLocale() const
{
return m_locale;
}
void Root::scheduleToUpdate(Install* aInstall)
{
bool wasEmpty = m_updateDeque.empty();
m_updateDeque.push_back(aInstall);
if (wasEmpty) {
aInstall->startUpdate();
}
}
void Root::startInstall(Install* aInstall)
{
if (m_delegate) {
m_delegate->startInstall(aInstall);
}
}
void Root::installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal)
{
if (m_delegate) {
m_delegate->installProgress(aInstall, aBytes, aTotal);
}
}
void Root::startNext(Install* aCurrent)
{
if (m_updateDeque.front() != aCurrent) {
SG_LOG(SG_GENERAL, SG_ALERT, "current install of package not head of the deque");
} else {
m_updateDeque.pop_front();
}
if (!m_updateDeque.empty()) {
m_updateDeque.front()->startUpdate();
}
}
void Root::finishInstall(Install* aInstall)
{
if (m_delegate) {
m_delegate->finishInstall(aInstall);
}
startNext(aInstall);
}
void Root::failedInstall(Install* aInstall, Delegate::FailureCode aReason)
{
SG_LOG(SG_GENERAL, SG_ALERT, "failed to install package:"
<< aInstall->package()->id() << ":" << aReason);
if (m_delegate) {
m_delegate->failedInstall(aInstall, aReason);
}
startNext(aInstall);
}
void Root::catalogRefreshBegin(Catalog* aCat)
{
m_refreshing.insert(aCat);
}
void Root::catalogRefreshComplete(Catalog* aCat, bool aSuccess)
{
m_refreshing.erase(aCat);
if (m_refreshing.empty()) {
if (m_delegate) {
m_delegate->refreshComplete();
}
}
}
} // of namespace pkg
} // of namespace simgear

110
simgear/package/Root.hxx Normal file
View File

@ -0,0 +1,110 @@
#ifndef SG_PACKAGE_ROOT_HXX
#define SG_PACKAGE_ROOT_HXX
#include <vector>
#include <map>
#include <deque>
#include <set>
#include <simgear/misc/sg_path.hxx>
#include <simgear/package/Delegate.hxx>
class SGPropertyNode;
namespace simgear
{
namespace HTTP { class Client; }
namespace pkg
{
// forward decls
class Package;
class Catalog;
class Install;
typedef std::vector<Package*> PackageList;
typedef std::vector<Catalog*> CatalogList;
typedef std::map<std::string, Catalog*> CatalogDict;
class Root
{
public:
Root(const SGPath& aPath);
virtual ~Root();
SGPath path() const
{ return m_path; }
void setLocale(const std::string& aLocale);
void setDelegate(Delegate* aDelegate);
std::string getLocale() const;
CatalogList catalogs() const;
void setMaxAgeSeconds(int seconds);
void setHTTPClient(HTTP::Client* aHTTP);
HTTP::Client* getHTTPClient() 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);
/**
* retrieve packages matching a filter.
* filter consists of required / minimum values, AND-ed together.
*/
PackageList packagesMatching(const SGPropertyNode* aFilter) const;
/**
* retrieve all the packages which are installed
* and have a pending update
*/
PackageList packagesNeedingUpdate() const;
Package* getPackageById(const std::string& aId) const;
Catalog* getCatalogById(const std::string& aId) const;
void scheduleToUpdate(Install* aInstall);
private:
friend class Install;
friend class Catalog;
void catalogRefreshBegin(Catalog* aCat);
void catalogRefreshComplete(Catalog* aCat, bool aSuccess);
void startNext(Install* aCurrent);
void startInstall(Install* aInstall);
void installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal);
void finishInstall(Install* aInstall);
void failedInstall(Install* aInstall, Delegate::FailureCode aReason);
SGPath m_path;
std::string m_locale;
HTTP::Client* m_http;
CatalogDict m_catalogs;
unsigned int m_maxAgeSeconds;
Delegate* m_delegate;
std::set<Catalog*> m_refreshing;
std::deque<Install*> m_updateDeque;
};
} // of namespace pkg
} // of namespace simgear
#endif // of SG_PACKAGE_ROOT_HXX

266
simgear/package/md5.c Normal file
View File

@ -0,0 +1,266 @@
/*
**********************************************************************
** md5.c **
** RSA Data Security, Inc. MD5 Message Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
**********************************************************************
*/
/*
**********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
**********************************************************************
*/
/* -- include the following line if the md5.h header file is separate -- */
#include "md5.h"
/* forward declaration */
static void Transform ();
static unsigned char PADDING[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* F, G and H are basic MD5 functions: selection, majority, parity */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
void MD5Init (MD5_CTX *mdContext)
{
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
/* Load magic initialization constants.
*/
mdContext->buf[0] = (UINT4)0x67452301;
mdContext->buf[1] = (UINT4)0xefcdab89;
mdContext->buf[2] = (UINT4)0x98badcfe;
mdContext->buf[3] = (UINT4)0x10325476;
}
void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* update number of bits */
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
mdContext->i[1]++;
mdContext->i[0] += ((UINT4)inLen << 3);
mdContext->i[1] += ((UINT4)inLen >> 29);
while (inLen--) {
/* add new character to buffer, increment mdi */
mdContext->in[mdi++] = *inBuf++;
/* transform if necessary */
if (mdi == 0x40) {
for (i = 0, ii = 0; i < 16; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
mdi = 0;
}
}
}
void MD5Final (MD5_CTX *mdContext)
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
unsigned int padLen;
/* save number of bits */
in[14] = mdContext->i[0];
in[15] = mdContext->i[1];
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* pad out to 56 mod 64 */
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
MD5Update (mdContext, PADDING, padLen);
/* append length in bits and transform */
for (i = 0, ii = 0; i < 14; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
/* store buffer in digest */
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
mdContext->digest[ii+1] =
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
mdContext->digest[ii+2] =
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
mdContext->digest[ii+3] =
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
}
}
/* Basic MD5 step. Transform buf based on in.
*/
static void Transform (buf, in)
UINT4 *buf;
UINT4 *in;
{
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */
FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */
FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */
FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */
FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */
FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */
FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */
FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */
FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */
FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */
FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */
FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */
FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */
FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */
FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */
FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */
/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */
GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */
GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */
GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */
GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */
GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */
GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */
GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */
GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */
GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */
GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */
GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */
GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */
GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */
GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */
GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */
/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */
HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */
HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */
HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */
HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */
HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */
HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */
HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */
HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */
HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */
HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */
HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */
HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */
HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */
HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */
HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */
/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */
II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */
II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */
II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */
II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */
II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */
II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */
II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */
II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */
II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */
II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */
II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */
II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */
II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */
II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */
II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

68
simgear/package/md5.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef SG_PACKAGE_MD5_H
#define SG_PACKAGE_MD5_H
/*
**********************************************************************
** md5.h -- Header file for implementation of MD5 **
** RSA Data Security, Inc. MD5 Message Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
** Revised (for MD5): RLR 4/27/91 **
** -- G modified to have y&~z instead of y&z **
** -- FF, GG, HH modified to add in last register done **
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
** -- distinct additive constant for each step **
** -- round 4 added, working mod 7 **
**********************************************************************
*/
/*
**********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
**********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
/* typedef a 32 bit type */
typedef unsigned int UINT4;
/* Data structure for MD5 (Message Digest) computation */
typedef struct {
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
UINT4 buf[4]; /* scratch buffer */
unsigned char in[64]; /* input buffer */
unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;
void MD5Init (MD5_CTX *mdContext);
void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);
void MD5Final (MD5_CTX *mdContext);
#ifdef __cplusplus
} // of extern C
#endif
#endif // of SG_PACKAGE_MD5_H

View File

@ -0,0 +1,86 @@
#include <simgear/io/HTTPClient.hxx>
#include <simgear/package/Catalog.hxx>
#include <simgear/package/Package.hxx>
#include <simgear/package/Install.hxx>
#include <simgear/package/Root.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <boost/foreach.hpp>
#include <iostream>
#include <cstring>
using namespace simgear;
using namespace std;
bool keepRunning = true;
int main(int argc, char** argv)
{
HTTP::Client* http = new HTTP::Client();
pkg::Root* root = new pkg::Root(Dir::current().path());
cout << "Package root is:" << Dir::current().path() << endl;
cout << "have " << pkg::Catalog::allCatalogs().size() << " catalog(s)" << endl;
root->setHTTPClient(http);
if (!strcmp(argv[1], "add")) {
std::string url(argv[2]);
pkg::Catalog::createFromUrl(root, url);
} else if (!strcmp(argv[1], "refresh")) {
root->refresh();
} else if (!strcmp(argv[1], "install")) {
pkg::Package* pkg = root->getPackageById(argv[2]);
if (!pkg) {
cerr << "unknown package:" << argv[2] << endl;
return EXIT_FAILURE;
}
if (pkg->isInstalled()) {
cout << "package " << pkg->id() << " is already installed at " << pkg->install()->path() << endl;
return EXIT_SUCCESS;
}
pkg::Catalog* catalog = pkg->catalog();
cout << "Will install:" << pkg->id() << " from " << catalog->id() <<
"(" << catalog->description() << ")" << endl;
pkg->install();
} else if (!strcmp(argv[1], "uninstall")) {
pkg::Package* pkg = root->getPackageById(argv[2]);
if (!pkg) {
cerr << "unknown package:" << argv[2] << endl;
return EXIT_FAILURE;
}
if (!pkg->isInstalled()) {
cerr << "package " << argv[2] << " not installed" << endl;
return EXIT_FAILURE;
}
cout << "Will uninstall:" << pkg->id() << endl;
pkg->install()->uninstall();
} else if (!strcmp(argv[1], "update-all")) {
pkg::PackageList updates = root->packagesNeedingUpdate();
BOOST_FOREACH(pkg::Package* p, updates) {
root->scheduleToUpdate(p->install());
}
} else if (!strcmp(argv[1], "list-updated")) {
pkg::PackageList updates = root->packagesNeedingUpdate();
if (updates.empty()) {
cout << "no packages with updates" << endl;
return EXIT_SUCCESS;
}
cout << updates.size() << " packages have updates" << endl;
BOOST_FOREACH(pkg::Package* p, updates) {
cout << "\t" << p->id() << " " << p->getLocalisedProp("name") << endl;
}
}
while (http->hasActiveRequests()) {
http->update();
}
return EXIT_SUCCESS;
}