The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
schema_validator.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2011 - 2025
3 by Sytyi Nick <nsytyi@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#pragma once
17
18#include "config_cache.hpp"
23
24#include <boost/graph/adjacency_list.hpp>
26#include <stack>
27#include <string>
28
29
30/** @file
31 * One of the realizations of serialization/validator.hpp abstract validator.
32 */
33namespace schema_validation
34{
35/**
36 * Realization of serialization/validator.hpp abstract validator.
37 * Based on stack. Uses some stacks to store different info.
38 */
40{
41public:
42 virtual ~schema_validator();
43
44 /**
45 * Initializes validator from file.
46 * Throws abstract_validator::error if any error.
47 */
48 schema_validator(const std::string& filename, bool validate_schema = false);
49
54
55 const std::vector<std::string>& get_errors() const
56 {
57 return errors_;
58 }
59
60 virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
61 virtual void close_tag() override;
62 virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
63 virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
64
65private:
66 // types section
67 // Just some magic to ensure zero initialization.
68 struct counter
69 {
70 int cnt;
72 : cnt(0)
73 {
74 }
75 };
76
77 /** Counters are mapped by tag name. */
78 typedef std::map<std::string, counter> cnt_map;
79
80 /** And counter maps are organize in stack. */
81 typedef std::stack<cnt_map> cnt_stack;
82
83protected:
84 using message_type = int;
86
87 /**
88 * Messages are cached.
89 * The reason is next: in file where [tag]...[/tag][+tag]...[/tag]
90 * config object will be validated each [/tag]. So message can be as wrong
91 * (when [+tag] section contains missed elements) as duplicated.
92 *
93 * Messages are mapped by config*. That ensures uniqueness.
94 * Also message-maps are organized in stack to avoid memory leaks.
95 */
97 {
99 std::string file;
100 int line;
101 int n;
102 std::string tag;
103 std::string key;
104 std::string value;
105 std::string expected;
106
107 message_info(message_type t, const std::string& file, int line = 0, int n = 0, const std::string& tag = "", const std::string& key = "", const std::string& value = "", const std::string& expected = "")
108 : type(t)
109 , file(file)
110 , line(line)
111 , n(n)
112 , tag(tag)
113 , key(key)
114 , value(value)
116 {
117 }
118 };
119
120 /** Controls the way to print errors. */
122
123 virtual void print(message_info&);
124private:
125 void print_cache();
126
127 typedef std::deque<message_info> message_list;
128 typedef std::map<const config*, message_list> message_map;
129
130 /** Reads config from input. */
131 bool read_config_file(const std::string& filename);
132
133 /** Shows, if validator is initialized with schema file. */
135
136 /** Root of schema information. */
138
139 std::stack<const wml_tag*> stack_;
140
141 /** Contains number of children. */
143
144 /** Caches error messages. */
145 std::stack<message_map> cache_;
146
147 /** Type validators. */
149
151
152 std::vector<std::string> errors_;
153
154protected:
155 template<typename... T>
156 void queue_message(const config& cfg, T&&... args)
157 {
158 cache_.top()[&cfg].emplace_back(std::forward<T>(args)...);
159 }
160
161 const wml_tag& active_tag() const;
162 std::string active_tag_path() const;
163 bool have_active_tag() const;
164 bool is_valid() const {return config_read_;}
165 wml_type::ptr find_type(const std::string& type) const;
166
167private:
168 using derivation_graph_t = boost::adjacency_list<boost::vecS,
169 boost::vecS,
170 boost::directedS,
171 std::pair<const wml_tag*, std::string>,
172 std::tuple<config, std::string, int>>;
173
175 std::map<const wml_tag*, derivation_graph_t::vertex_descriptor> derivation_map_;
176
178
179 /**
180 * Collects all mandatory keys for a tag, including the super keys and overrides.
181 *
182 * The returned map can contain non-mandatory keys if they are overriden, please check the is_mandatory() result.
183 */
184 utils::optional<std::map<std::string, wml_key>> find_mandatory_keys(const wml_tag* tag, const config& cfg) const;
185 utils::optional<std::map<std::string, wml_key>> find_mandatory_keys(
186 const wml_tag* tag, const config& cfg, std::vector<const wml_tag*>& visited) const;
187
188 /**
189 * Validates that all mandatory keys for a tag are present.
190 */
192 const wml_tag* tag, const config& cfg, const std::string& name, int start_line, const std::string& file);
193 void validate_mandatory_keys(const std::map<std::string, wml_key>& mandatory_keys,
194 const wml_tag* tag,
195 const config& cfg,
196 const std::string& name,
197 int start_line,
198 const std::string& file,
199 std::vector<const wml_tag*>& visited);
200
201 using link_graph_t = boost::adjacency_list<boost::vecS,
202 boost::vecS,
203 boost::directedS,
204 std::string>;
205
206 using link_graph_map_t = std::map<const wml_type_alias*,
207 link_graph_t::vertex_descriptor>;
208
209 void detect_link_cycles(const std::string& filename);
210 void collect_link_source(link_graph_t& link_graph, link_graph_map_t& link_map, const std::string& type_name, const wml_type* type);
211 void collect_link_target(link_graph_t& link_graph, link_graph_map_t& link_map, const std::string& type_name, const wml_type* type, const wml_type_alias* alias);
212};
213
214// A validator specifically designed for validating a schema
215// In addition to the usual, it verifies that references within the schema are valid, for example via the [link] tag
217{
218public:
220 virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
221 virtual void close_tag() override;
222 virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
223 virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
224private:
225 struct reference {
226 reference(const std::string& value, const std::string& file, int line, const std::string& tag)
227 : value_(value)
228 , file_(file)
229 , tag_(tag)
230 , line_(line)
231 {}
232 std::string value_, file_, tag_;
233 int line_;
234 bool match(const std::set<std::string>& with) const;
235 bool can_find(const wml_tag& root, const config& cfg) const;
236 bool operator<(const reference& other) const;
237 };
238 std::string current_path() const;
239 std::set<std::string> defined_types_, defined_tag_paths_;
241 std::stack<std::string> tag_stack_;
242 std::map<std::string, std::string> links_;
243 std::multimap<std::string, std::string> derivations_;
245 bool tag_path_exists(const config& cfg, const reference& ref);
246 void check_for_duplicates(const std::string& name, std::vector<std::string>& seen, const config& cfg, message_type type, const std::string& file, int line, const std::string& tag);
247 static bool name_matches(const std::string& pattern, const std::string& name);
248
249 void print(message_info& message) override;
251
253 = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, std::string, std::pair<config, reference>>;
254
256 std::map<std::string, schema_derivation_graph_t::vertex_descriptor> schema_derivation_map_;
257
259};
260
261} // namespace schema_validation{
double t
Used in parsing config file.
Definition validator.hpp:38
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
virtual void open_tag(const std::string &name, const config &parent, int start_line=0, const std::string &file="", bool addition=false) override
Is called when parser opens tag.
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
std::multimap< std::string, std::string > derivations_
std::map< std::string, std::string > links_
boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, std::string, std::pair< config, reference > > schema_derivation_graph_t
bool tag_path_exists(const config &cfg, const reference &ref)
schema_derivation_graph_t schema_derivation_graph_
void print(message_info &message) override
void check_for_duplicates(const std::string &name, std::vector< std::string > &seen, const config &cfg, message_type type, const std::string &file, int line, const std::string &tag)
std::map< std::string, schema_derivation_graph_t::vertex_descriptor > schema_derivation_map_
static bool name_matches(const std::string &pattern, const std::string &name)
virtual void validate_key(const config &cfg, const std::string &name, const config_attribute_value &value, int start_line, const std::string &file) override
Checks if key is allowed and if its value is valid What exactly is validated depends on validator rea...
Realization of serialization/validator.hpp abstract validator.
bool read_config_file(const std::string &filename)
Reads config from input.
wml_type::map types_
Type validators.
wml_tag root_
Root of schema information.
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
bool create_exceptions_
Controls the way to print errors.
boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, std::string > link_graph_t
boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, std::pair< const wml_tag *, std::string >, std::tuple< config, std::string, int > > derivation_graph_t
utils::optional< std::map< std::string, wml_key > > find_mandatory_keys(const wml_tag *tag, const config &cfg) const
Collects all mandatory keys for a tag, including the super keys and overrides.
wml_type::ptr find_type(const std::string &type) const
void collect_link_source(link_graph_t &link_graph, link_graph_map_t &link_map, const std::string &type_name, const wml_type *type)
std::stack< message_map > cache_
Caches error messages.
std::map< const config *, message_list > message_map
void queue_message(const config &cfg, T &&... args)
cnt_stack counter_
Contains number of children.
virtual void validate_key(const config &cfg, const std::string &name, const config_attribute_value &value, int start_line, const std::string &file) override
Checks if key is allowed and if its value is valid What exactly is validated depends on validator rea...
std::stack< cnt_map > cnt_stack
And counter maps are organize in stack.
std::deque< message_info > message_list
std::map< const wml_type_alias *, link_graph_t::vertex_descriptor > link_graph_map_t
const std::vector< std::string > & get_errors() const
bool config_read_
Shows, if validator is initialized with schema file.
void detect_link_cycles(const std::string &filename)
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
void validate_mandatory_keys(const wml_tag *tag, const config &cfg, const std::string &name, int start_line, const std::string &file)
Validates that all mandatory keys for a tag are present.
void collect_link_target(link_graph_t &link_graph, link_graph_map_t &link_map, const std::string &type_name, const wml_type *type, const wml_type_alias *alias)
std::map< const wml_tag *, derivation_graph_t::vertex_descriptor > derivation_map_
virtual void open_tag(const std::string &name, const config &parent, int start_line=0, const std::string &file="", bool addition=false) override
Is called when parser opens tag.
std::stack< const wml_tag * > stack_
std::map< std::string, counter > cnt_map
Counters are mapped by tag name.
virtual void print(message_info &)
Stores information about tag.
Definition tag.hpp:48
Stores information about a schema type.
Definition type.hpp:66
Stores information about a schema type.
Definition type.hpp:36
std::map< std::string, ptr > map
Definition type.hpp:43
std::shared_ptr< wml_type > ptr
Definition type.hpp:42
const config * cfg
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
std::string filename
Filename.
bool match(const std::set< std::string > &with) const
bool can_find(const wml_tag &root, const config &cfg) const
reference(const std::string &value, const std::string &file, int line, const std::string &tag)
message_info(message_type t, const std::string &file, int line=0, int n=0, const std::string &tag="", const std::string &key="", const std::string &value="", const std::string &expected="")
This file contains object "tag", which is used to store information about tags while annotation parsi...
This file contains object "type", which is used to store information about types while annotation par...
This file contains information about validation abstract level interface.