Commit dd02b363 by Maarten L. Hekkelman

externalize resources

parent 54728d49
...@@ -4,9 +4,25 @@ ...@@ -4,9 +4,25 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <cassert>
#include "cif++/Config.h" #include "cif++/Config.h"
struct rsrc_imp
{
unsigned int m_next;
unsigned int m_child;
unsigned int m_name;
unsigned int m_size;
unsigned int m_data;
};
#if USE_RSRC
extern const rsrc_imp gResourceIndex[];
extern const char gResourceData[];
extern const char gResourceName[];
#endif
namespace cif namespace cif
{ {
...@@ -155,4 +171,88 @@ class Progress ...@@ -155,4 +171,88 @@ class Progress
struct ProgressImpl* mImpl; struct ProgressImpl* mImpl;
}; };
// --------------------------------------------------------------------
// The new default is to load 'resource' files from the file system
// since not everyone likes mrc. But if you do want to use mrc to load
// resources, specify the compile time flag USE_RSRC.
/// \brief Simple class containing the data for a resource
class rsrc
{
public:
rsrc()
: m_data(nullptr), m_size(0) {}
rsrc(const char* data, size_t size)
: m_data(data), m_size(size) {}
rsrc(const rsrc& rhs)
: m_data(rhs.m_data), m_size(rhs.m_size) {}
rsrc& operator=(const rsrc& rhs)
{
m_data = rhs.m_data;
m_size = rhs.m_size;
return *this;
}
explicit operator bool()
{
return m_data != nullptr and m_size > 0;
}
const char* data() const { return m_data; }
size_t size() const { return m_size; }
private:
const char* m_data;
size_t m_size;
};
/// \brief loader types
enum class rsrc_loader_type { mrsrc, file };
/// \brief loader info
struct rsrc_loader_info
{
rsrc_loader_type type;
std::string info;
const void* ptrs[3];
};
class rsrc_loader
{
public:
static void init(std::initializer_list<rsrc_loader_info> loaders =
{
#if USE_RSRC
{ rsrc_loader_type::mrsrc, "", { gResourceIndex, gResourceData, gResourceName } },
#endif
{ rsrc_loader_type::file, "." }
})
{
assert(not s_instance);
s_instance.reset(new rsrc_loader(loaders));
}
static rsrc load(const std::string& name)
{
assert(s_instance);
return s_instance->do_load(name);
}
~rsrc_loader();
private:
rsrc_loader(const std::initializer_list<rsrc_loader_info>& loaders);
rsrc do_load(const std::string& name);
static std::unique_ptr<rsrc_loader> s_instance;
std::list<struct rsrc_loader_impl*> m_loaders;
};
} }
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
#include "cif++/Cif++.h" #include "cif++/Cif++.h"
//// the std regex of gcc is crashing.... //// the std regex of gcc is crashing....
#include <boost/regex.hpp> // #include <boost/regex.hpp>
// #include <regex> #include <regex>
#include <set> #include <set>
namespace cif namespace cif
...@@ -38,7 +38,7 @@ struct ValidateType ...@@ -38,7 +38,7 @@ struct ValidateType
{ {
std::string mName; std::string mName;
DDL_PrimitiveType mPrimitiveType; DDL_PrimitiveType mPrimitiveType;
boost::regex mRx; std::regex mRx;
bool operator<(const ValidateType& rhs) const bool operator<(const ValidateType& rhs) const
{ {
......
...@@ -13,7 +13,8 @@ namespace mmcif ...@@ -13,7 +13,8 @@ namespace mmcif
class Structure; class Structure;
class Monomer; class Monomer;
extern const double kCouplingConstant, kMinHBondEnergy, kMaxHBondEnergy; extern const double
kCouplingConstant, kMinHBondEnergy, kMaxHBondEnergy;
enum SecondaryStructureType : char enum SecondaryStructureType : char
{ {
......
// Copyright Maarten L. Hekkelman 2006-2010
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MRSRC_H
#define MRSRC_H
#include <string>
#include <list>
#include <exception>
namespace mrsrc
{
class rsrc_not_found_exception : public std::exception
{
public:
virtual const char* what() const throw() { return "resource not found"; }
};
class rsrc;
typedef std::list<rsrc> rsrc_list;
}
// --------------------------------------------------------------------
// By default, we assume mrc is used to create the resources. If you need
// local disk storage instead, use the NO_RSRC macro. See below for
// usage.
#if defined(USE_RSRC)
/*
Resources are data sources for the application.
They are retrieved by name.
Basic usage:
mrsrc::rsrc rsrc("dialogs/my-cool-dialog.glade");
if (rsrc)
{
GladeXML* glade = glade_xml_new_from_buffer(rsrc.data(), rsrc.size(), NULL, "japi");
...
}
*/
namespace mrsrc {
struct rsrc_imp
{
unsigned int m_next;
unsigned int m_child;
unsigned int m_name;
unsigned int m_size;
unsigned int m_data;
};
}
// The following three variables are generated by the japi resource compiler:
extern const mrsrc::rsrc_imp gResourceIndex[];
extern const char gResourceData[];
extern const char gResourceName[];
namespace mrsrc
{
class rsrc
{
public:
rsrc() : m_impl(gResourceIndex) {}
rsrc(const rsrc& other)
: m_impl(other.m_impl) {}
rsrc& operator=(const rsrc& other)
{
m_impl = other.m_impl;
return *this;
}
rsrc(const std::string& path);
std::string name() const { return gResourceName + m_impl->m_name; }
const char* data() const { return gResourceData + m_impl->m_data; }
unsigned long size() const { return m_impl->m_size; }
operator bool () const { return m_impl != NULL and m_impl->m_size > 0; }
rsrc_list children() const;
private:
rsrc(const rsrc_imp* imp)
: m_impl(imp) {}
const rsrc_imp* m_impl;
};
inline
rsrc_list rsrc::children() const
{
rsrc_list result;
if (m_impl->m_child)
{
const rsrc_imp* impl = gResourceIndex + m_impl->m_child;
result.push_back(rsrc(impl));
while (impl->m_next)
{
impl = gResourceIndex + impl->m_next;
result.push_back(rsrc(impl));
}
}
return result;
}
inline
rsrc::rsrc(const std::string& path)
{
// static_assert(sizeof(m_impl->m_next) == 4, "invalid size for unsigned int");
m_impl = gResourceIndex;
std::string p(path);
// would love to use boost functions here, but then the dependancies
// should be minimal of course.
while (not p.empty())
{
if (m_impl->m_child == 0) // no children, this is an error
throw rsrc_not_found_exception();
m_impl = gResourceIndex + m_impl->m_child;
std::string::size_type s = p.find('/');
std::string name;
if (s != std::string::npos)
{
name = p.substr(0, s);
p.erase(0, s + 1);
}
else
std::swap(name, p);
while (name != gResourceName + m_impl->m_name)
{
if (m_impl->m_next == 0)
throw rsrc_not_found_exception();
m_impl = gResourceIndex + m_impl->m_next;
}
}
}
}
#else
// --------------------------------------------------------------------
// Fall back option for resources, locate the data in the path specified
// in then environment variable RESOURCE_DIR
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
namespace mrsrc
{
namespace detail
{
class rsrc_loader
{
public:
static rsrc_loader& instance()
{
static rsrc_loader sInstance;
return sInstance;
}
const std::vector<char>& load(const std::string& path)
{
if (not m_loaded.count(path))
{
std::string p = m_rsrc_dir + '/' + path;
std::ifstream file(p);
std::vector<char> result;
if (file.is_open())
{
std::streambuf* b = file.rdbuf();
size_t length = b->pubseekoff(0, std::ios::end);
b->pubseekpos(0);
result.resize(length);
b->sgetn(result.data(), length);
}
m_loaded.emplace(path, std::move(result));
}
return m_loaded.at(path);
}
private:
rsrc_loader()
{
const char* rsrc_dir = getenv("RESOURCE_DIR");
#if defined(RSRC_DIR)
if (rsrc_dir == nullptr)
rsrc_dir = RSRC_DIR;
#endif
if (rsrc_dir == nullptr)
{
char pb[PATH_MAX];
const char* cwd = getcwd(pb, PATH_MAX);
if (cwd == nullptr)
throw std::runtime_error("Could not locate resource directory nor current directory");
std::cerr << "RESOURCE_DIR not defined, falling back to " << cwd << std::endl;
rsrc_dir = cwd;
}
m_rsrc_dir = rsrc_dir;
}
std::string m_rsrc_dir;
std::map<std::string,std::vector<char>> m_loaded;
};
}
class rsrc
{
public:
rsrc(const rsrc&) = delete;
rsrc& operator=(const rsrc&) = delete;
rsrc(const std::string& path)
: m_data(detail::rsrc_loader::instance().load(path))
// , m_name(path)
{}
// std::string name() const { return m_name; }
const char* data() const { return m_data.data(); }
unsigned long size() const { return m_data.size(); }
explicit operator bool () const { return not m_data.empty(); }
// rsrc_list children() const;
private:
const std::vector<char>& m_data;
// const std::string m_name;
};
}
#endif
#endif
...@@ -24,8 +24,6 @@ namespace fs = boost::filesystem; ...@@ -24,8 +24,6 @@ namespace fs = boost::filesystem;
#include <boost/iostreams/filter/gzip.hpp> #include <boost/iostreams/filter/gzip.hpp>
#include <boost/logic/tribool.hpp> #include <boost/logic/tribool.hpp>
#include "cif++/mrsrc.h"
#include "cif++/Cif++.h" #include "cif++/Cif++.h"
#include "cif++/CifParser.h" #include "cif++/CifParser.h"
#include "cif++/CifValidator.h" #include "cif++/CifValidator.h"
...@@ -3021,7 +3019,7 @@ void File::loadDictionary(const char* dict) ...@@ -3021,7 +3019,7 @@ void File::loadDictionary(const char* dict)
} }
catch (...) {} catch (...) {}
mrsrc::rsrc dictData(dictFile.string()); auto dictData = rsrc_loader::load(dictFile.string());
if (dictData) if (dictData)
{ {
......
...@@ -1046,7 +1046,7 @@ bool DictParser::collectItemTypes() ...@@ -1046,7 +1046,7 @@ bool DictParser::collectItemTypes()
try try
{ {
ValidateType v = { ValidateType v = {
code, mapToPrimitiveType(primitiveCode), boost::regex(construct, boost::regex::extended | boost::regex::optimize) code, mapToPrimitiveType(primitiveCode), std::regex(construct, std::regex::extended | std::regex::optimize)
}; };
mValidator.addTypeValidator(move(v)); mValidator.addTypeValidator(move(v));
......
...@@ -29,6 +29,8 @@ namespace ba = boost::algorithm; ...@@ -29,6 +29,8 @@ namespace ba = boost::algorithm;
namespace cif namespace cif
{ {
extern int VERBOSE;
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// This really makes a difference, having our own tolower routines // This really makes a difference, having our own tolower routines
...@@ -630,5 +632,120 @@ void Progress::message(const std::string& inMessage) ...@@ -630,5 +632,120 @@ void Progress::message(const std::string& inMessage)
} }
} }
// --------------------------------------------------------------------
std::unique_ptr<rsrc_loader> rsrc_loader::s_instance;
struct rsrc_loader_impl
{
virtual ~rsrc_loader_impl() {}
virtual rsrc load(const std::string& path) const = 0;
};
class rsrc_not_found_exception : public std::exception
{
public:
virtual const char* what() const throw() { return "resource not found"; }
};
struct mrsrc_rsrc_loader_impl : public rsrc_loader_impl
{
mrsrc_rsrc_loader_impl(const rsrc_loader_info& info);
virtual rsrc load(const std::string& path) const;
const rsrc_imp* m_index;
const char* m_data;
const char* m_name;
};
mrsrc_rsrc_loader_impl::mrsrc_rsrc_loader_impl(const rsrc_loader_info& info)
{
m_index = static_cast<const rsrc_imp*>(info.ptrs[0]);
m_data = reinterpret_cast<const char*>(info.ptrs[1]);
m_name = reinterpret_cast<const char*>(info.ptrs[2]);
}
rsrc mrsrc_rsrc_loader_impl::load(const std::string& path) const
{
auto node = m_index;
std::string p(path);
while (not p.empty())
{
if (node->m_child == 0) // no children, this is an error
return {};
node = m_index + node->m_child;
std::string::size_type s = p.find('/');
std::string name;
if (s != std::string::npos)
{
name = p.substr(0, s);
p.erase(0, s + 1);
}
else
std::swap(name, p);
while (name != m_name + node->m_name)
{
if (node->m_next == 0)
return {};
node = m_index + node->m_next;
}
}
return { m_data + node->m_data, node->m_size };
}
rsrc_loader::rsrc_loader(const std::initializer_list<rsrc_loader_info>& loaders)
{
for (auto& l: loaders)
{
try
{
switch (l.type)
{
case rsrc_loader_type::file:
break;
case rsrc_loader_type::mrsrc:
m_loaders.push_back(new mrsrc_rsrc_loader_impl(l));
break;
default:
break;
}
}
catch (const std::exception& e)
{
if (VERBOSE)
std::cerr << e.what() << std::endl;
}
}
}
rsrc_loader::~rsrc_loader()
{
for (auto l: m_loaders)
delete l;
}
rsrc rsrc_loader::do_load(const std::string& name)
{
rsrc result;
for (auto loader: m_loaders)
{
result = loader->load(name);
if (result)
break;
}
return result;
}
} }
...@@ -162,7 +162,7 @@ void ValidateItem::operator()(string value) const ...@@ -162,7 +162,7 @@ void ValidateItem::operator()(string value) const
{ {
if (not value.empty() and value != "?" and value != ".") if (not value.empty() and value != "?" and value != ".")
{ {
if (mType != nullptr and not boost::regex_match(value, mType->mRx)) if (mType != nullptr and not std::regex_match(value, mType->mRx))
throw ValidationError(mCategory->mName, mTag, "Value '" + value + "' does not match type expression for type " + mType->mName); throw ValidationError(mCategory->mName, mTag, "Value '" + value + "' does not match type expression for type " + mType->mName);
if (not mEnums.empty()) if (not mEnums.empty())
...@@ -219,7 +219,7 @@ const ValidateType* Validator::getValidatorForType(string typeCode) const ...@@ -219,7 +219,7 @@ const ValidateType* Validator::getValidatorForType(string typeCode) const
{ {
const ValidateType* result = nullptr; const ValidateType* result = nullptr;
auto i = mTypeValidators.find(ValidateType{ typeCode, ptChar, boost::regex() }); auto i = mTypeValidators.find(ValidateType{ typeCode, ptChar, std::regex() });
if (i != mTypeValidators.end()) if (i != mTypeValidators.end())
result = &*i; result = &*i;
else if (VERBOSE > 4) else if (VERBOSE > 4)
......
...@@ -21,8 +21,6 @@ namespace fs = boost::filesystem; ...@@ -21,8 +21,6 @@ namespace fs = boost::filesystem;
#include "cif++/Compound.h" #include "cif++/Compound.h"
#include "cif++/CifUtils.h" #include "cif++/CifUtils.h"
#include "cif++/mrsrc.h"
using namespace std; using namespace std;
namespace ba = boost::algorithm; namespace ba = boost::algorithm;
...@@ -87,9 +85,7 @@ class IsomerDB ...@@ -87,9 +85,7 @@ class IsomerDB
IsomerDB::IsomerDB() IsomerDB::IsomerDB()
{ {
// #if defined(USE_RSRC) auto isomers = cif::rsrc_loader::load("isomers.txt");
mrsrc::rsrc isomers("isomers.txt");
// mrsrc::rsrc isomers("isomers-with-sugar.xml");
if (not isomers) if (not isomers)
throw runtime_error("Missing isomers.txt resource"); throw runtime_error("Missing isomers.txt resource");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment