The Battle for Wesnoth  1.17.14+dev
schema_validator.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2022
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  virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
57  virtual void close_tag() override;
58  virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
59  virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
60 
61 private:
62  // types section
63  // Just some magic to ensure zero initialization.
64  struct counter
65  {
66  int cnt;
68  : cnt(0)
69  {
70  }
71  };
72 
73  /** Counters are mapped by tag name. */
74  typedef std::map<std::string, counter> cnt_map;
75 
76  /** And counter maps are organize in stack. */
77  typedef std::stack<cnt_map> cnt_stack;
78 
79 protected:
80  using message_type = int;
82 
83  /**
84  * Messages are cached.
85  * The reason is next: in file where [tag]...[/tag][+tag]...[/tag]
86  * config object will be validated each [/tag]. So message can be as wrong
87  * (when [+tag] section contains missed elements) as duplicated.
88  *
89  * Messages are mapped by config*. That ensures uniqueness.
90  * Also message-maps are organized in stack to avoid memory leaks.
91  */
92  struct message_info
93  {
95  std::string file;
96  int line;
97  int n;
98  std::string tag;
99  std::string key;
100  std::string value;
101  std::string expected;
102 
103  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 = "")
104  : type(t)
105  , file(file)
106  , line(line)
107  , n(n)
108  , tag(tag)
109  , key(key)
110  , value(value)
111  , expected(expected)
112  {
113  }
114  };
115 
116  /** Controls the way to print errors. */
118 
119  virtual void print(message_info&);
120 private:
121  void print_cache();
122 
123  typedef std::deque<message_info> message_list;
124  typedef std::map<const config*, message_list> message_map;
125 
126  /** Reads config from input. */
127  bool read_config_file(const std::string& filename);
128 
129  /** Shows, if validator is initialized with schema file. */
131 
132  /** Root of schema information. */
134 
135  std::stack<const wml_tag*> stack_;
136 
137  /** Contains number of children. */
138  cnt_stack counter_;
139 
140  /** Caches error messages. */
141  std::stack<message_map> cache_;
142 
143  /** Type validators. */
145 
147 
148 protected:
149  template<typename... T>
150  void queue_message(const config& cfg, T&&... args)
151  {
152  cache_.top()[&cfg].emplace_back(std::forward<T>(args)...);
153  }
154 
155  const wml_tag& active_tag() const;
156  std::string active_tag_path() const;
157  bool have_active_tag() const;
158  bool is_valid() const {return config_read_;}
159  wml_type::ptr find_type(const std::string& type) const;
160 };
161 
162 // A validator specifically designed for validating a schema
163 // In addition to the usual, it verifies that references within the schema are valid, for example via the [link] tag
165 {
166 public:
168  virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
169  virtual void close_tag() override;
170  virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
171  virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
172 private:
173  struct reference {
174  reference(const std::string& value, const std::string& file, int line, const std::string& tag)
175  : value_(value)
176  , file_(file)
177  , tag_(tag)
178  , line_(line)
179  {}
180  std::string value_, file_, tag_;
181  int line_;
182  bool match(const std::set<std::string>& with);
183  bool can_find(const wml_tag& root, const config& cfg);
184  bool operator<(const reference& other) const;
185  };
186  std::string current_path() const;
187  std::set<std::string> defined_types_, defined_tag_paths_;
188  std::vector<reference> referenced_types_, referenced_tag_paths_;
189  std::stack<std::string> tag_stack_;
190  std::map<std::string, std::string> links_;
191  std::multimap<std::string, std::string> derivations_;
192  int type_nesting_, condition_nesting_;
193  bool tag_path_exists(const config& cfg, const reference& ref);
194  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);
195  static bool name_matches(const std::string& pattern, const std::string& name);
196 
197  void print(message_info& message) override;
198  enum { WRONG_TYPE = NEXT_ERROR, WRONG_PATH, DUPLICATE_TAG, DUPLICATE_KEY, SUPER_LOOP, NEXT_ERROR };
199 };
200 
201 } // namespace schema_validation{
std::stack< cnt_map > cnt_stack
And counter maps are organize in stack.
std::stack< const wml_tag * > stack_
bool create_exceptions_
Controls the way to print errors.
cnt_stack counter_
Contains number of children.
This file contains object "type", which is used to store information about types while annotation par...
std::multimap< std::string, std::string > derivations_
Variant for storing WML attributes.
Stores information about tag.
Definition: tag.hpp:47
std::deque< message_info > message_list
This file contains information about validation abstract level interface.
std::map< const config *, message_list > message_map
wml_tag root_
Root of schema information.
std::map< std::string, ptr > map
Definition: type.hpp:43
bool config_read_
Shows, if validator is initialized with schema file.
This file contains object "tag", which is used to store information about tags while annotation parsi...
Used in parsing config file.
Definition: validator.hpp:37
std::stack< message_map > cache_
Caches error messages.
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...
wml_type::map types_
Type validators.
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="")
schema_validator(const std::string &filename, bool validate_schema=false)
Initializes validator from file.
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:171
bool read_config_file(const std::string &filename)
Reads config from input.
static bool operator<(const placing_info &a, const placing_info &b)
Definition: game_state.cpp:109
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
std::shared_ptr< wml_type > ptr
Definition: type.hpp:42
void queue_message(const config &cfg, T &&... args)
This file contains object "key", which is used to store information about keys while annotation parsi...
double t
Definition: astarsearch.cpp:65
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.
Realization of serialization/validator.hpp abstract validator.
wml_type::ptr find_type(const std::string &type) const
std::map< std::string, counter > cnt_map
Counters are mapped by tag name.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
reference(const std::string &value, const std::string &file, int line, const std::string &tag)
virtual void print(message_info &)
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
std::map< std::string, std::string > links_