mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 22:14:24 +08:00
Compare commits
3 Commits
v10.0.4
...
combined-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
228e90a515 | ||
|
|
04c4ecc265 | ||
|
|
3ce3630b50 |
@@ -178,7 +178,7 @@ class category
|
||||
/// @brief Set the validator for this category to @a v
|
||||
/// @param v The category_validator to assign. A nullptr value is allowed.
|
||||
/// @param db The enclosing @ref datablock
|
||||
void set_validator(const validator *v, datablock &db);
|
||||
void set_validator(const validator_base *v, datablock &db);
|
||||
|
||||
/// @brief Update the links in this category
|
||||
/// @param db The enclosing @ref datablock
|
||||
@@ -186,7 +186,7 @@ class category
|
||||
|
||||
/// @brief Return the global @ref validator for the data
|
||||
/// @return The @ref validator or nullptr if not assigned
|
||||
const validator *get_validator() const { return m_validator; }
|
||||
const validator_base *get_validator() const { return m_validator; }
|
||||
|
||||
/// @brief Return the category validator for this category
|
||||
/// @return The @ref category_validator or nullptr if not assigned
|
||||
@@ -1285,7 +1285,7 @@ class category
|
||||
|
||||
std::string m_name;
|
||||
std::vector<item_entry> m_items;
|
||||
const validator *m_validator = nullptr;
|
||||
const validator_base *m_validator = nullptr;
|
||||
const category_validator *m_cat_validator = nullptr;
|
||||
std::vector<link> m_parent_links, m_child_links;
|
||||
bool m_cascade = true;
|
||||
|
||||
@@ -116,14 +116,14 @@ class datablock : public std::list<category>
|
||||
*
|
||||
* @param v The new validator object, may be null
|
||||
*/
|
||||
void set_validator(const validator *v);
|
||||
void set_validator(const validator_base *v);
|
||||
|
||||
/**
|
||||
* @brief Get the validator object
|
||||
*
|
||||
* @return const validator* The validator or nullptr if there is none
|
||||
*/
|
||||
const validator *get_validator() const;
|
||||
const validator_base *get_validator() const;
|
||||
|
||||
/**
|
||||
* @brief Validates the content of this datablock and all its content
|
||||
@@ -244,7 +244,7 @@ class datablock : public std::list<category>
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
const validator *m_validator = nullptr;
|
||||
const validator_base *m_validator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
@@ -42,9 +42,4 @@ namespace cif
|
||||
*/
|
||||
validator parse_dictionary(std::string_view name, std::istream &is);
|
||||
|
||||
/**
|
||||
* @brief Extend the definitions in validator @a v with the contents of stream @a is
|
||||
*/
|
||||
void extend_dictionary(validator &v, std::istream &is);
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -205,10 +205,10 @@ class file : public std::list<datablock>
|
||||
void load(std::istream &is);
|
||||
|
||||
/** Load the data from the file specified by @a p using validator @a v */
|
||||
void load(const std::filesystem::path &p, const validator &v);
|
||||
void load(const std::filesystem::path &p, const validator_base &v);
|
||||
|
||||
/** Load the data from @a is using validator @a v */
|
||||
void load(std::istream &is, const validator &v);
|
||||
void load(std::istream &is, const validator_base &v);
|
||||
|
||||
/** Load the data from the file specified by @a p using a validator constructed from dictionary @a dict */
|
||||
void load(const std::filesystem::path &p, std::string_view dict);
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class validator;
|
||||
class validator_base;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -310,7 +310,7 @@ class parser : public sac_parser
|
||||
{
|
||||
public:
|
||||
/// \brief constructor, generates data into @a file from @a is using validator @a v
|
||||
parser(std::istream &is, file &file, const validator *v)
|
||||
parser(std::istream &is, file &file, const validator_base *v)
|
||||
: sac_parser(is)
|
||||
, m_file(file)
|
||||
, m_validator(v)
|
||||
@@ -337,7 +337,7 @@ class parser : public sac_parser
|
||||
file &m_file;
|
||||
datablock *m_datablock = nullptr;
|
||||
category *m_category = nullptr;
|
||||
const validator *m_validator = nullptr;
|
||||
const validator_base *m_validator = nullptr;
|
||||
row_handle m_row;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <filesystem>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
@@ -48,6 +49,7 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
struct category_validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -384,57 +386,32 @@ struct link_validator
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief The validator class combines all the link, category and item validator classes
|
||||
*
|
||||
*/
|
||||
class validator
|
||||
class validator_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
*/
|
||||
validator(std::string_view name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
~validator() = default;
|
||||
virtual ~validator_base() = default;
|
||||
|
||||
validator(const validator &rhs) = delete;
|
||||
validator &operator=(const validator &rhs) = delete;
|
||||
validator_base(const validator_base &rhs) = delete;
|
||||
validator_base &operator=(const validator_base &rhs) = delete;
|
||||
|
||||
/// @brief move constructor
|
||||
validator(validator &&rhs) = default;
|
||||
validator_base(validator_base &&rhs) = default;
|
||||
|
||||
/// @brief move assignment operator
|
||||
validator &operator=(validator &&rhs) = default;
|
||||
|
||||
friend class dictionary_parser;
|
||||
|
||||
/// @brief Add type_validator @a v to the list of type validators
|
||||
void add_type_validator(type_validator &&v);
|
||||
validator_base &operator=(validator_base &&rhs) = default;
|
||||
|
||||
/// @brief Return the type validator for @a type_code, may return nullptr
|
||||
const type_validator *get_validator_for_type(std::string_view type_code) const;
|
||||
|
||||
/// @brief Add category_validator @a v to the list of category validators
|
||||
void add_category_validator(category_validator &&v);
|
||||
virtual const type_validator *get_validator_for_type(std::string_view type_code) const = 0;
|
||||
|
||||
/// @brief Return the category validator for @a category, may return nullptr
|
||||
const category_validator *get_validator_for_category(std::string_view category) const;
|
||||
|
||||
/// @brief Add link_validator @a v to the list of link validators
|
||||
void add_link_validator(link_validator &&v);
|
||||
virtual const category_validator *get_validator_for_category(std::string_view category) const = 0;
|
||||
|
||||
/// @brief Return the list of link validators for which the parent is @a category
|
||||
std::vector<const link_validator *> get_links_for_parent(std::string_view category) const;
|
||||
virtual std::vector<const link_validator *> get_links_for_parent(std::string_view category) const = 0;
|
||||
|
||||
/// @brief Return the list of link validators for which the child is @a category
|
||||
std::vector<const link_validator *> get_links_for_child(std::string_view category) const;
|
||||
virtual std::vector<const link_validator *> get_links_for_child(std::string_view category) const = 0;
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(validation_error err, bool fatal = true) const
|
||||
@@ -456,19 +433,87 @@ class validator
|
||||
void report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const;
|
||||
|
||||
const std::string &name() const { return m_name; } ///< Get the name of this validator
|
||||
void set_name(const std::string &name) { m_name = name; } ///< Set the name of this validator
|
||||
const std::string &name() const { return m_name; } ///< Get the name of this validator
|
||||
const std::string &version() const { return m_version; } ///< Get the version of this validator
|
||||
bool is_strict() const { return m_strict; } ///< Get the strict flag of this validator
|
||||
|
||||
const std::string &version() const { return m_version; } ///< Get the version of this validator
|
||||
protected:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
*/
|
||||
validator_base(std::string_view name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
validator_base() = default;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_version;
|
||||
bool m_strict = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The validator class combines all the link, category and item validator classes
|
||||
*
|
||||
*/
|
||||
class validator : public validator_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
*/
|
||||
validator(std::string_view name)
|
||||
: validator_base(name)
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
~validator() = default;
|
||||
|
||||
validator(const validator &rhs) = delete;
|
||||
validator &operator=(const validator &rhs) = delete;
|
||||
|
||||
/// @brief move constructor
|
||||
validator(validator &&rhs) = default;
|
||||
|
||||
/// @brief move assignment operator
|
||||
validator &operator=(validator &&rhs) = default;
|
||||
|
||||
friend class dictionary_parser;
|
||||
|
||||
/// @brief Add type_validator @a v to the list of type validators
|
||||
void add_type_validator(type_validator &&v);
|
||||
|
||||
/// @brief Return the type validator for @a type_code, may return nullptr
|
||||
const type_validator *get_validator_for_type(std::string_view type_code) const override;
|
||||
|
||||
/// @brief Add category_validator @a v to the list of category validators
|
||||
void add_category_validator(category_validator &&v);
|
||||
|
||||
/// @brief Return the category validator for @a category, may return nullptr
|
||||
const category_validator *get_validator_for_category(std::string_view category) const override;
|
||||
|
||||
/// @brief Add link_validator @a v to the list of link validators
|
||||
void add_link_validator(link_validator &&v);
|
||||
|
||||
/// @brief Return the list of link validators for which the parent is @a category
|
||||
std::vector<const link_validator *> get_links_for_parent(std::string_view category) const override;
|
||||
|
||||
/// @brief Return the list of link validators for which the child is @a category
|
||||
std::vector<const link_validator *> get_links_for_child(std::string_view category) const override;
|
||||
|
||||
void set_name(const std::string &name) { m_name = name; } ///< Set the name of this validator
|
||||
void set_version(const std::string &version) { m_version = version; } ///< Set the version of this validator
|
||||
|
||||
private:
|
||||
// name is fully qualified here:
|
||||
item_validator *get_validator_for_item(std::string_view name) const;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_version;
|
||||
bool m_strict = false;
|
||||
std::set<type_validator> m_type_validators;
|
||||
std::set<category_validator> m_category_validators;
|
||||
std::vector<link_validator> m_link_validators;
|
||||
@@ -476,6 +521,46 @@ class validator
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class extended_validator : public validator_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
* @param validators The validators this extended validator is composed off
|
||||
*/
|
||||
extended_validator(std::vector<const validator *> validators);
|
||||
|
||||
extended_validator(const extended_validator &rhs) = delete;
|
||||
extended_validator &operator=(const extended_validator &rhs) = delete;
|
||||
|
||||
/// @brief move constructor
|
||||
extended_validator(extended_validator &&rhs) = default;
|
||||
|
||||
/// @brief move assignment operator
|
||||
extended_validator &operator=(extended_validator &&rhs) = default;
|
||||
|
||||
/// @brief Return the type validator for @a type_code, may return nullptr
|
||||
virtual const type_validator *get_validator_for_type(std::string_view type_code) const override;
|
||||
|
||||
/// @brief Return the category validator for @a category, may return nullptr
|
||||
virtual const category_validator *get_validator_for_category(std::string_view category) const override;
|
||||
|
||||
/// @brief Return the list of link validators for which the parent is @a category
|
||||
virtual std::vector<const link_validator *> get_links_for_parent(std::string_view category) const override;
|
||||
|
||||
/// @brief Return the list of link validators for which the child is @a category
|
||||
virtual std::vector<const link_validator *> get_links_for_child(std::string_view category) const override;
|
||||
|
||||
protected:
|
||||
friend class validator_factory;
|
||||
|
||||
std::vector<const validator *> m_validators;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Validators are globally unique objects, use the validator_factory
|
||||
* class to construct them. This class is a singleton.
|
||||
@@ -488,18 +573,36 @@ class validator_factory
|
||||
static validator_factory &instance();
|
||||
|
||||
/// @brief Return the validator with name @a dictionary_name
|
||||
const validator &operator[](std::string_view dictionary_name);
|
||||
[[deprecated("use construct_validator(const category &audit_conform) instead")]]
|
||||
const validator_base &operator[](std::string_view dictionary_name);
|
||||
|
||||
/// @brief Return a validator for the data contained in an audit_conform category
|
||||
const validator_base &construct_validator(const category &audit_conform);
|
||||
|
||||
/// @brief Construct a new validator with name @a name from resource data with at least version @a version if specified
|
||||
const validator &construct_validator(std::string_view name,
|
||||
std::optional<std::string> version);
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is with at least version @a version if specified
|
||||
const validator &construct_validator(std::string_view name,
|
||||
std::optional<std::string> version, std::istream &is);
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is
|
||||
const validator &construct_validator(std::string_view name, std::istream &is);
|
||||
const validator &construct_validator(std::string_view name, std::istream &is)
|
||||
{
|
||||
return construct_validator(name, {}, is);
|
||||
}
|
||||
|
||||
private:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
validator_factory() = default;
|
||||
|
||||
static bool check_version(std::string_view name, std::string_view expected, std::string_view found);
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::list<validator> m_validators;
|
||||
std::list<extended_validator> m_extended_validators;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -617,7 +617,7 @@ std::set<uint16_t> category::key_item_indices() const
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void category::set_validator(const validator *v, datablock &db)
|
||||
void category::set_validator(const validator_base *v, datablock &db)
|
||||
{
|
||||
m_validator = v;
|
||||
|
||||
@@ -696,7 +696,7 @@ bool category::is_valid() const
|
||||
bool result = true;
|
||||
|
||||
if (m_validator == nullptr)
|
||||
throw std::runtime_error("no Validator specified");
|
||||
throw std::runtime_error("no validator specified");
|
||||
|
||||
if (empty())
|
||||
{
|
||||
|
||||
@@ -41,25 +41,7 @@ datablock::datablock(const datablock &db)
|
||||
void datablock::load_dictionary()
|
||||
{
|
||||
if (auto *audit_conform = get("audit_conform"); audit_conform and not audit_conform->empty())
|
||||
{
|
||||
std::string name = audit_conform->front().get<std::string>("dict_name");
|
||||
|
||||
if (name == "mmcif_pdbx_v50")
|
||||
name = "mmcif_pdbx.dic"; // we had a bug here in libcifpp...
|
||||
|
||||
if (not name.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
load_dictionary(name);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
if (VERBOSE)
|
||||
std::cerr << "Failed to load dictionary " << std::quoted(name) << ": " << ex.what() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
set_validator(&validator_factory::instance().construct_validator(*audit_conform));
|
||||
}
|
||||
|
||||
void datablock::load_dictionary(std::string_view name)
|
||||
@@ -67,7 +49,7 @@ void datablock::load_dictionary(std::string_view name)
|
||||
set_validator(&validator_factory::instance()[name]);
|
||||
}
|
||||
|
||||
void datablock::set_validator(const validator *v)
|
||||
void datablock::set_validator(const validator_base *v)
|
||||
{
|
||||
m_validator = v;
|
||||
|
||||
@@ -83,7 +65,7 @@ void datablock::set_validator(const validator *v)
|
||||
}
|
||||
}
|
||||
|
||||
const validator *datablock::get_validator() const
|
||||
const validator_base *datablock::get_validator() const
|
||||
{
|
||||
return m_validator;
|
||||
}
|
||||
@@ -108,7 +90,7 @@ bool datablock::is_valid()
|
||||
bool result = true;
|
||||
for (auto &cat : *this)
|
||||
result = cat.is_valid() and result;
|
||||
|
||||
|
||||
// Add or remove the audit_conform block here.
|
||||
if (result)
|
||||
{
|
||||
@@ -129,7 +111,9 @@ bool datablock::is_valid()
|
||||
}
|
||||
}
|
||||
else
|
||||
erase(std::find_if(begin(), end(), [](category &cat) { return cat.name() == "audit_conform"; }), end());
|
||||
erase(std::find_if(begin(), end(), [](category &cat)
|
||||
{ return cat.name() == "audit_conform"; }),
|
||||
end());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -203,7 +187,7 @@ std::tuple<datablock::iterator, bool> datablock::emplace(std::string_view name)
|
||||
|
||||
if (is_new)
|
||||
{
|
||||
i = insert(end(), {name});
|
||||
i = insert(end(), { name });
|
||||
i->set_validator(m_validator, *this);
|
||||
}
|
||||
|
||||
@@ -264,7 +248,7 @@ namespace
|
||||
return std::get<2>(*i);
|
||||
}
|
||||
|
||||
void calculate_cat_order(cat_order_t &cat_order, iter_t i, const validator &validator)
|
||||
void calculate_cat_order(cat_order_t &cat_order, iter_t i, const validator_base &validator)
|
||||
{
|
||||
if (i == cat_order.end() or get_count(i) >= 0)
|
||||
return;
|
||||
@@ -337,7 +321,7 @@ void datablock::write(std::ostream &os) const
|
||||
else
|
||||
{
|
||||
// mmcif support, sort of. First write the 'entry' Category
|
||||
// and if it exists, _AND_ we have a Validator, write out the
|
||||
// and if it exists, _AND_ we have a validator, write out the
|
||||
// audit_conform record.
|
||||
|
||||
if (auto entry = get("entry"); entry != nullptr)
|
||||
|
||||
@@ -488,11 +488,4 @@ validator parse_dictionary(std::string_view name, std::istream &is)
|
||||
return result;
|
||||
}
|
||||
|
||||
void extend_dictionary(validator &v, std::istream &is)
|
||||
{
|
||||
file f;
|
||||
dictionary_parser p(v, is, f);
|
||||
p.load_dictionary();
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -176,7 +176,7 @@ void file::load(std::istream &is, std::string_view dict)
|
||||
load(is, validator_factory::instance().operator[](dict));
|
||||
}
|
||||
|
||||
void file::load(const std::filesystem::path &p, const validator &v)
|
||||
void file::load(const std::filesystem::path &p, const validator_base &v)
|
||||
{
|
||||
gzio::ifstream in(p);
|
||||
if (not in.is_open())
|
||||
@@ -192,7 +192,7 @@ void file::load(const std::filesystem::path &p, const validator &v)
|
||||
}
|
||||
}
|
||||
|
||||
void file::load(std::istream &is, const validator &v)
|
||||
void file::load(std::istream &is, const validator_base &v)
|
||||
{
|
||||
parser p(is, *this);
|
||||
p.parse_file();
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
namespace cif::pdb
|
||||
{
|
||||
|
||||
condition get_parents_condition(const validator &validator, row_handle rh, const category &parentCat)
|
||||
condition get_parents_condition(const validator_base &validator, row_handle rh, const category &parentCat)
|
||||
{
|
||||
condition result;
|
||||
|
||||
|
||||
362
src/validate.cpp
362
src/validate.cpp
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "cif++/validate.hpp"
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
@@ -284,6 +285,27 @@ const item_validator *category_validator::get_validator_for_aliased_item(std::st
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void validator_base::report_error(std::error_code ec, bool fatal) const
|
||||
{
|
||||
if (m_strict or fatal)
|
||||
throw validation_exception(ec);
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ec.message() << '\n';
|
||||
}
|
||||
|
||||
void validator_base::report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal) const
|
||||
{
|
||||
auto ex = item.empty() ? validation_exception(ec, category) : validation_exception(ec, category, item);
|
||||
|
||||
if (m_strict or fatal)
|
||||
throw ex;
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ex.what() << '\n';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void validator::add_type_validator(type_validator &&v)
|
||||
{
|
||||
auto r = m_type_validators.insert(std::move(v));
|
||||
@@ -397,23 +419,76 @@ std::vector<const link_validator *> validator::get_links_for_child(std::string_v
|
||||
return result;
|
||||
}
|
||||
|
||||
void validator::report_error(std::error_code ec, bool fatal) const
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
extended_validator::extended_validator(std::vector<const validator *> validators)
|
||||
: m_validators(validators)
|
||||
{
|
||||
if (m_strict or fatal)
|
||||
throw validation_exception(ec);
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ec.message() << '\n';
|
||||
std::vector<std::string> names, versions;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
names.emplace_back(v->name());
|
||||
versions.emplace_back(v->version());
|
||||
m_strict = m_strict or v->is_strict();
|
||||
}
|
||||
|
||||
m_name = cif::join(names, "; ");
|
||||
m_version = cif::join(versions, "; ");
|
||||
}
|
||||
|
||||
void validator::report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal) const
|
||||
const type_validator *extended_validator::get_validator_for_type(std::string_view type_code) const
|
||||
{
|
||||
auto ex = item.empty() ? validation_exception(ec, category) : validation_exception(ec, category, item);
|
||||
const type_validator *result = nullptr;
|
||||
|
||||
if (m_strict or fatal)
|
||||
throw ex;
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ex.what() << '\n';
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
result = v->get_validator_for_type(type_code);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const category_validator *extended_validator::get_validator_for_category(std::string_view category) const
|
||||
{
|
||||
const category_validator *result = nullptr;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
result = v->get_validator_for_category(category);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const link_validator *> extended_validator::get_links_for_parent(std::string_view category) const
|
||||
{
|
||||
std::vector<const link_validator *> result;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
auto links = v->get_links_for_parent(category);
|
||||
result.insert(result.end(), links.begin(), links.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const link_validator *> extended_validator::get_links_for_child(std::string_view category) const
|
||||
{
|
||||
std::vector<const link_validator *> result;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
auto links = v->get_links_for_child(category);
|
||||
result.insert(result.end(), links.begin(), links.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -424,113 +499,172 @@ validator_factory &validator_factory::instance()
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
const validator &validator_factory::operator[](std::string_view dictionary_name)
|
||||
const validator_base &validator_factory::operator[](std::string_view dictionary_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
category audit_conform("audit_conform");
|
||||
for (auto part : cif::split(dictionary_name, ";", true))
|
||||
audit_conform.emplace({ { "dict_name", part } });
|
||||
|
||||
for (auto &validator : m_validators)
|
||||
{
|
||||
if (iequals(validator.name(), dictionary_name))
|
||||
return validator;
|
||||
}
|
||||
|
||||
// not found, try to see if it helps if we tweak the name a little
|
||||
|
||||
// too bad clang version 10 did not have a constructor for std::filesystem::path that accepts a std::string_view
|
||||
std::filesystem::path dictionary(dictionary_name.data(), dictionary_name.data() + dictionary_name.length());
|
||||
|
||||
if (dictionary.extension() != ".dic")
|
||||
{
|
||||
auto dict_name = dictionary.filename().string() + ".dic";
|
||||
|
||||
for (auto &validator : m_validators)
|
||||
{
|
||||
if (iequals(validator.name(), dict_name))
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
|
||||
// not found, add it
|
||||
|
||||
validator v(dictionary_name);
|
||||
|
||||
for (bool first = true; auto part_name : cif::split(dictionary_name, ";", true))
|
||||
{
|
||||
auto data = load_resource(part_name);
|
||||
dictionary.assign(part_name.begin(), part_name.end());
|
||||
|
||||
if (not data and dictionary.extension().string() != ".dic")
|
||||
data = load_resource(dictionary.parent_path() / (dictionary.filename().string() + ".dic"));
|
||||
|
||||
if (not data)
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
// might be a compressed dictionary on disk
|
||||
std::filesystem::path p = dictionary;
|
||||
if (p.extension() == ".dic")
|
||||
p = p.parent_path() / (p.filename().string() + ".gz");
|
||||
else
|
||||
p = p.parent_path() / (p.filename().string() + ".dic.gz");
|
||||
|
||||
#if defined(CACHE_DIR) or defined(DATA_DIR)
|
||||
if (not std::filesystem::exists(p, ec) or ec)
|
||||
{
|
||||
for (const char *dir : {
|
||||
# if defined(CACHE_DIR)
|
||||
CACHE_DIR,
|
||||
# endif
|
||||
# if defined(DATA_DIR)
|
||||
DATA_DIR
|
||||
# endif
|
||||
})
|
||||
{
|
||||
auto p2 = std::filesystem::path(dir) / p;
|
||||
if (std::filesystem::exists(p2, ec) and not ec)
|
||||
{
|
||||
swap(p, p2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (std::filesystem::exists(p, ec) and not ec)
|
||||
{
|
||||
auto in = std::make_unique<gzio::ifstream>(p);
|
||||
|
||||
if (not in->is_open())
|
||||
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
|
||||
|
||||
data.reset(in.release());
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
|
||||
}
|
||||
|
||||
if (std::exchange(first, false))
|
||||
v = parse_dictionary(part_name, *data);
|
||||
else
|
||||
extend_dictionary(v, *data);
|
||||
}
|
||||
|
||||
m_validators.emplace_back(std::move(v));
|
||||
|
||||
return m_validators.back();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
std::string msg = "Error while loading dictionary ";
|
||||
msg += dictionary_name;
|
||||
std::throw_with_nested(std::runtime_error(msg));
|
||||
}
|
||||
return construct_validator(audit_conform);
|
||||
}
|
||||
|
||||
const validator &validator_factory::construct_validator(std::string_view name, std::istream &is)
|
||||
const validator_base &validator_factory::construct_validator(const category &audit_conform)
|
||||
{
|
||||
return m_validators.emplace_back(parse_dictionary(name, is));
|
||||
if (audit_conform.empty())
|
||||
throw std::runtime_error("Empty audit_conform category, cannot create a validator");
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
std::vector<const validator *> validators;
|
||||
|
||||
for (const auto &[name, version] : audit_conform.rows<std::string, std::optional<std::string>>("dict_name", "dict_version"))
|
||||
{
|
||||
auto &v = construct_validator(name, version);
|
||||
validators.emplace_back(&v);
|
||||
}
|
||||
|
||||
if (validators.size() == 1)
|
||||
return *validators.front();
|
||||
|
||||
// override mode, last dictionary is most important
|
||||
std::reverse(validators.begin(), validators.end());
|
||||
|
||||
for (auto &ev : m_extended_validators)
|
||||
{
|
||||
if (ev.m_validators == validators)
|
||||
return ev;
|
||||
}
|
||||
|
||||
return m_extended_validators.emplace_back(validators);
|
||||
}
|
||||
|
||||
const validator &validator_factory::construct_validator(std::string_view name,
|
||||
std::optional<std::string> version)
|
||||
{
|
||||
for (auto &v : m_validators)
|
||||
{
|
||||
if (version.has_value())
|
||||
check_version(name, *version, v.version());
|
||||
|
||||
if (v.name() == name)
|
||||
return v;
|
||||
}
|
||||
|
||||
std::filesystem::path dictionary(name);
|
||||
|
||||
auto data = load_resource(name);
|
||||
|
||||
if (not data and dictionary.extension().string() != ".dic")
|
||||
data = load_resource(dictionary.parent_path() / (dictionary.filename().string() + ".dic"));
|
||||
|
||||
if (not data)
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
// might be a compressed dictionary on disk
|
||||
std::filesystem::path p = dictionary;
|
||||
if (p.extension() == ".dic")
|
||||
p = p.parent_path() / (p.filename().string() + ".gz");
|
||||
else
|
||||
p = p.parent_path() / (p.filename().string() + ".dic.gz");
|
||||
|
||||
#if defined(CACHE_DIR) or defined(DATA_DIR)
|
||||
if (not std::filesystem::exists(p, ec) or ec)
|
||||
{
|
||||
for (const char *dir : {
|
||||
# if defined(CACHE_DIR)
|
||||
CACHE_DIR,
|
||||
# endif
|
||||
# if defined(DATA_DIR)
|
||||
DATA_DIR
|
||||
# endif
|
||||
})
|
||||
{
|
||||
auto p2 = std::filesystem::path(dir) / p;
|
||||
if (std::filesystem::exists(p2, ec) and not ec)
|
||||
{
|
||||
swap(p, p2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (std::filesystem::exists(p, ec) and not ec)
|
||||
{
|
||||
auto in = std::make_unique<gzio::ifstream>(p);
|
||||
|
||||
if (not in->is_open())
|
||||
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
|
||||
|
||||
data.reset(in.release());
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
|
||||
}
|
||||
|
||||
return construct_validator(name, version, *data);
|
||||
}
|
||||
|
||||
const validator &validator_factory::construct_validator(std::string_view name,
|
||||
std::optional<std::string> version, std::istream &is)
|
||||
{
|
||||
auto v = parse_dictionary(name, is);
|
||||
|
||||
if (version.has_value() and VERBOSE >= 0)
|
||||
{
|
||||
auto vv = v.version();
|
||||
|
||||
if (vv.empty())
|
||||
std::clog << "Could not check version of dictionary " << name << " since this info is missing\n";
|
||||
else
|
||||
check_version(name, *version, vv);
|
||||
}
|
||||
|
||||
return m_validators.emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
bool validator_factory::check_version(std::string_view name, std::string_view expected, std::string_view found)
|
||||
{
|
||||
bool result = true;
|
||||
auto el = cif::split(expected, ".");
|
||||
auto fl = cif::split(found, ".");
|
||||
|
||||
auto eli = el.begin();
|
||||
auto fli = fl.begin();
|
||||
|
||||
while (eli != el.end() and fli != fl.end())
|
||||
{
|
||||
int e_int, f_int;
|
||||
if (auto [ptr, ec] = std::from_chars(eli->begin(), eli->end(), e_int); ec != std::errc{})
|
||||
{
|
||||
std::clog << "Could not parse requested version string for dictionary " << std::quoted(expected) << "\n";
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto [ptr, ec] = std::from_chars(fli->begin(), fli->end(), f_int); ec != std::errc{})
|
||||
{
|
||||
std::clog << "Could not parse version string in dictionary " << name << " " << std::quoted(found) << "\n";
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (f_int > e_int) // newer version, assume this is ok
|
||||
break;
|
||||
|
||||
if (f_int < e_int)
|
||||
{
|
||||
std::clog << "The version in dictionary " << name << " is lower than requested, this may cause validation errors\n";
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
++eli;
|
||||
++fli;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
Reference in New Issue
Block a user