1 /*
2    Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include "config_cache.hpp"
18 #include "serialization/parser.hpp"
19 #include "serialization/tag.hpp"
20 #include "serialization/validator.hpp"
21 
22 #include <boost/regex.hpp>
23 
24 #include <iostream>
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  */
40 class schema_validator : public abstract_validator
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);
50 
set_create_exceptions(bool value)51 	void set_create_exceptions(bool value)
52 	{
53 		create_exceptions_ = value;
54 	}
55 
56 	virtual void open_tag(
57 			const std::string& name, int start_line = 0, const std::string& file = "", bool addittion = false);
58 	virtual void close_tag();
59 	virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file);
60 	virtual void validate_key(const config& cfg,
61 			const std::string& name,
62 			const std::string& value,
63 			int start_line,
64 			const std::string& file);
65 
66 private:
67 	// types section
68 	// Just some magic to ensure zero initialization.
69 	struct counter
70 	{
71 		int cnt;
counterschema_validation::schema_validator::counter72 		counter()
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 	enum message_type { WRONG_TAG, EXTRA_TAG, MISSING_TAG, EXTRA_KEY, MISSING_KEY, WRONG_VALUE };
85 	// error_cache
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 	 */
96 	struct message_info
97 	{
98 		message_type type;
99 		std::string file;
100 		int line;
101 		int n;
102 		std::string tag;
103 		std::string key;
104 		std::string value;
105 
message_infoschema_validation::schema_validator::message_info106 		message_info(message_type t,
107 				const std::string& file,
108 				int line = 0,
109 				int n = 0,
110 				const std::string& tag = "",
111 				const std::string& key = "",
112 				const std::string& value = "")
113 			: type(t)
114 			, file(file)
115 			, line(line)
116 			, n(n)
117 			, tag(tag)
118 			, key(key)
119 			, value(value)
120 		{
121 		}
122 	};
123 
124 	typedef std::deque<message_info> message_list;
125 	typedef std::map<const config*, message_list> message_map;
126 
127 	void print(message_info&);
128 
129 	/** Reads config from input. */
130 	bool read_config_file(const std::string& filename);
131 
132 	/** Shows, if validator is initialized with schema file. */
133 	bool config_read_;
134 
135 	/** Controls the way to print errors. */
136 	bool create_exceptions_;
137 
138 	/** Root of schema information. */
139 	class_tag root_;
140 
141 	std::stack<const class_tag*> stack_;
142 
143 	/** Contains number of children. */
144 	cnt_stack counter_;
145 
146 	/** Caches error messages. */
147 	std::stack<message_map> cache_;
148 
149 	/** Type validators. */
150 	std::map<std::string, boost::regex> types_;
151 };
152 } // namespace schema_validation{
153