Add initial validator structure.

Applies a slightly modified patch #2815.
This commit is contained in:
Mark de Wever 2011-07-26 20:01:17 +00:00
parent 351a3d803d
commit 01169bbd31
4 changed files with 134 additions and 18 deletions

View file

@ -31,6 +31,7 @@
#include "serialization/preprocessor.hpp"
#include "serialization/tokenizer.hpp"
#include "serialization/string_utils.hpp"
#include "serialization/validator.hpp"
#include "foreach.hpp"
#include <stack>
@ -48,14 +49,14 @@ static lg::log_domain log_config("config");
static const size_t max_recursion_levels = 1000;
namespace {
class parser
{
parser();
parser(const parser&);
parser& operator=(const parser&);
public:
parser(config& cfg, std::istream& in);
parser(config& cfg, std::istream& in,
abstract_validator * validator = NULL);
~parser();
void operator()();
@ -68,6 +69,7 @@ private:
config& cfg_;
tokenizer *tok_;
abstract_validator *validator_;
struct element {
element(config *cfg, std::string const &name,
@ -84,10 +86,11 @@ private:
std::stack<element> elements;
};
parser::parser(config &cfg, std::istream &in) :
cfg_(cfg),
tok_(new tokenizer(in)),
elements()
parser::parser(config &cfg, std::istream &in, abstract_validator * validator)
:cfg_(cfg),
tok_(new tokenizer(in)),
validator_(validator),
elements()
{
}
@ -148,13 +151,15 @@ void parser::parse_element()
tok_->next_token();
std::string elname;
config* current_element = NULL;
switch(tok_->current_token().type) {
case token::STRING: // [element]
elname = tok_->current_token().value;
if (tok_->next_token().type != ']')
error(_("Unterminated [element] tag"));
if (validator_){
validator_->open_tag(elname,tok_->get_start_line(),
tok_->get_file());
}
// Add the element
current_element = &(elements.top().cfg->add_child(elname));
elements.push(element(current_element, elname, tok_->get_start_line(), tok_->get_file()));
@ -174,6 +179,10 @@ void parser::parse_element()
} else {
current_element = &elements.top().cfg->add_child(elname);
}
if (validator_){
validator_->open_tag(elname,tok_->get_start_line(),
tok_->get_file());
}
elements.push(element(current_element, elname, tok_->get_start_line(), tok_->get_file()));
break;
@ -194,7 +203,11 @@ void parser::parse_element()
error(lineno_string(i18n_symbols, ss.str(),
N_("Found invalid closing tag $tag2 for tag $tag1 (opened at $pos)")));
}
if(validator_){
element & el= elements.top();
validator_->validate(*el.cfg,el.name,el.start_line,el.file);
validator_->close_tag();
}
elements.pop();
break;
default:
@ -342,18 +355,18 @@ void parser::error(const std::string& error_type)
} // end anon namespace
void read(config &cfg, std::istream &in)
void read(config &cfg, std::istream &in, abstract_validator * validator)
{
parser(cfg, in)();
parser(cfg, in, validator)();
}
void read(config &cfg, std::string &in)
void read(config &cfg, std::string &in, abstract_validator * validator)
{
std::istringstream ss(in);
parser(cfg, ss)();
parser(cfg, ss, validator)();
}
void read_gz(config &cfg, std::istream &file)
void read_gz(config &cfg, std::istream &file, abstract_validator * validator)
{
//an empty gzip file seems to confuse boost on msvc
//so return early if this is the case
@ -364,7 +377,7 @@ void read_gz(config &cfg, std::istream &file)
filter.push(boost::iostreams::gzip_decompressor());
filter.push(file);
parser(cfg, filter)();
parser(cfg, filter,validator)();
}
static std::string escaped_string(const std::string &value)

View file

@ -22,10 +22,15 @@
#include "global.hpp"
#include "config.hpp"
class abstract_validator;
// Read data in, clobbering existing data.
void read(config &cfg, std::istream &in); // Throws config::error
void read(config &cfg, std::string &in); // Throws config::error
void read_gz(config &cfg, std::istream &in);
void read(config &cfg, std::istream &in,
abstract_validator * validator = NULL); // Throws config::error
void read(config &cfg, std::string &in,
abstract_validator * validator = NULL); // Throws config::error
void read_gz(config &cfg, std::istream &in,
abstract_validator * validator = NULL);
void write(std::ostream &out, config const &cfg, unsigned int level=0);
void write_gz(std::ostream &out, config const &cfg);

View file

@ -0,0 +1,19 @@
/* $Id$ */
/*
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file validator.cpp
*/
#include "serialization/validator.hpp"

View file

@ -0,0 +1,79 @@
/* $Id$ */
/*
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file validator.hpp
* This file contains information about validation abstract level interface.
*/
#ifndef SERIALIZATION_VALIDATOR_HPP_INCLUDED
#define SERIALIZATION_VALIDATOR_HPP_INCLUDED
#include "game_errors.hpp"
#include <string>
class config;
/**
* @class abstract_validator
* Used in parsing config file. @ref parser.cpp
* Contains virtual methods, which are called by parser
* and take information about config to be validated
*/
class abstract_validator
{
public:
/**
* Constructor of validator can throw validator::error
* @throws abstract_validator::error
*/
abstract_validator(){}
virtual ~abstract_validator(){}
/**
* Is called when parser opens tag.
* @param name Name of tag
* @param start_line Line in file
* @param file Name of file
*/
virtual void open_tag(const std::string & name,int start_line,
const std::string &file) = 0;
/**
* As far as parser is built on stack, some realizations can store stack
* too. So they need to know if tag was closed.
*/
virtual void close_tag() = 0;
/**
* Validates config
* What exactly is validated depends on validator realization
* @param cfg Config to be validated.
* @param name Name of tag
* @param start_line Line in file
* @param file Name of file
*/
virtual bool validate(const config & cfg, const std::string & name,
int start_line,
const std::string &file) = 0;
/**
* @struct error
* Used to manage with not initialized validators
* Supposed to be thrown from the constructor
*/
struct error : public game::error {
error(const std::string& message) : game::error(message) {}
};
};
#endif // SERIALIZATION_VALIDATOR_HPP_INCLUDED