The Battle for Wesnoth  1.17.21+dev
schema_validator.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2023
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"
19 #include "serialization/parser.hpp"
24 
25 #include <queue>
26 #include <stack>
27 #include <string>
28 
29 class config;
30 
31 /** @file
32  * One of the realizations of serialization/validator.hpp abstract validator.
33  */
34 namespace schema_validation
35 {
36 /**
37  * Realization of serialization/validator.hpp abstract validator.
38  * Based on stack. Uses some stacks to store different info.
39  */
41 {
42 public:
43  virtual ~schema_validator();
44 
45  /**
46  * Initializes validator from file.
47  * Throws abstract_validator::error if any error.
48  */
49  schema_validator(const std::string& filename, bool validate_schema = false);
50 
51  void set_create_exceptions(bool value)
52  {
53  create_exceptions_ = value;
54  }
55 
56  const std::vector<std::string>& get_errors() const
57  {
58  return errors_;
59  }
60 
61  virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
62  virtual void close_tag() override;
63  virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
64  virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
65 
66 private:
67  // types section
68  // Just some magic to ensure zero initialization.
69  struct counter
70  {
71  int cnt;
73  : cnt(0)
74  {
75  }
76  };
77 
78  /** Counters are mapped by tag name. */
79  typedef std::map<std::string, counter> cnt_map;
80 
81  /** And counter maps are organize in stack. */
82  typedef std::stack<cnt_map> cnt_stack;
83 
84 protected:
85  using message_type = int;
87 
88  /**
89  * Messages are cached.
90  * The reason is next: in file where [tag]...[/tag][+tag]...[/tag]
91  * config object will be validated each [/tag]. So message can be as wrong
92  * (when [+tag] section contains missed elements) as duplicated.
93  *
94  * Messages are mapped by config*. That ensures uniqueness.
95  * Also message-maps are organized in stack to avoid memory leaks.
96  */
97  struct message_info
98  {
100  std::string file;
101  int line;
102  int n;
103  std::string tag;
104  std::string key;
105  std::string value;
106  std::string expected;
107 
108  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 = "")
109  : type(t)
110  , file(file)
111  , line(line)
112  , n(n)
113  , tag(tag)
114  , key(key)
115  , value(value)
116  , expected(expected)
117  {
118  }
119  };
120 
121  /** Controls the way to print errors. */
123 
124  virtual void print(message_info&);
125 private:
126  void print_cache();
127 
128  typedef std::deque<message_info> message_list;
129  typedef std::map<const config*, message_list> message_map;
130 
131  /** Reads config from input. */
132  bool read_config_file(const std::string& filename);
133 
134  /** Shows, if validator is initialized with schema file. */
136 
137  /** Root of schema information. */
139 
140  std::stack<const wml_tag*> stack_;
141 
142  /** Contains number of children. */
144 
145  /** Caches error messages. */
146  std::stack<message_map> cache_;
147 
148  /** Type validators. */
150 
152 
153  std::vector<std::string> errors_;
154 
155 protected:
156  template<typename... T>
157  void queue_message(const config& cfg, T&&... args)
158  {
159  cache_.top()[&cfg].emplace_back(std::forward<T>(args)...);
160  }
161 
162  const wml_tag& active_tag() const;
163  std::string active_tag_path() const;
164  bool have_active_tag() const;
165  bool is_valid() const {return config_read_;}
166  wml_type::ptr find_type(const std::string& type) const;
167 };
168 
169 // A validator specifically designed for validating a schema
170 // In addition to the usual, it verifies that references within the schema are valid, for example via the [link] tag
172 {
173 public:
175  virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
176  virtual void close_tag() override;
177  virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
178  virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
179 private:
180  struct reference {
181  reference(const std::string& value, const std::string& file, int line, const std::string& tag)
182  : value_(value)
183  , file_(file)
184  , tag_(tag)
185  , line_(line)
186  {}
187  std::string value_, file_, tag_;
188  int line_;
189  bool match(const std::set<std::string>& with);
190  bool can_find(const wml_tag& root, const config& cfg);
191  bool operator<(const reference& other) const;
192  };
193  std::string current_path() const;
194  std::set<std::string> defined_types_, defined_tag_paths_;
195  std::vector<reference> referenced_types_, referenced_tag_paths_;
196  std::stack<std::string> tag_stack_;
197  std::map<std::string, std::string> links_;
198  std::multimap<std::string, std::string> derivations_;
200  bool tag_path_exists(const config& cfg, const reference& ref);
201  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);
202  static bool name_matches(const std::string& pattern, const std::string& name);
203 
204  void print(message_info& message) override;
206 };
207 
208 } // namespace schema_validation{
double t
Definition: astarsearch.cpp:65
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:161
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::vector< reference > referenced_tag_paths_
std::map< std::string, std::string > links_
bool tag_path_exists(const config &cfg, const reference &ref)
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)
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.
const std::vector< std::string > & get_errors() const
wml_type::map types_
Type validators.
wml_tag root_
Root of schema information.
std::vector< std::string > errors_
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
schema_validator(const std::string &filename, bool validate_schema=false)
Initializes validator from file.
bool create_exceptions_
Controls the way to print errors.
wml_type::ptr find_type(const std::string &type) const
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
bool config_read_
Shows, if validator is initialized with schema file.
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
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
std::map< std::string, ptr > map
Definition: type.hpp:43
std::shared_ptr< wml_type > ptr
Definition: type.hpp:42
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:171
This file contains object "key", which is used to store information about keys while annotation parsi...
reference(const std::string &value, const std::string &file, int line, const std::string &tag)
bool match(const std::set< std::string > &with)
bool can_find(const wml_tag &root, const config &cfg)
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.