ogre config-style configfile loader

#ifndef SH_CONFIG_LOADER_H__
#define SH_CONFIG_LOADER_H__
 
#include <map>
#include <vector>
#include <cassert>
#include <string>
 
namespace sh
{
    class ConfigNode;
 
	class ConfigLoader
	{
	public:
		static void loadAllFiles(ConfigLoader* c, const std::string& path);
 
		ConfigLoader(const std::string& fileEnding);
		virtual ~ConfigLoader();
 
		std::string m_fileEnding;
 
		// For a line like
		// entity animals/dog
		// {
		//    ...
		// }
		// The type is "entity" and the name is "animals/dog"
		// Or if animal/dog was not there then name is ""
		virtual ConfigNode *getConfigScript (const std::string &name);
 
		virtual std::map <std::string, ConfigNode*> getAllConfigScripts ();
 
		virtual void parseScript(std::ifstream &stream);
 
 
	protected:
 
		float m_LoadOrder;
		// like "*.object"
 
		std::map <std::string, ConfigNode*> m_scriptList;
 
		enum Token
		{
			TOKEN_Text,
			TOKEN_NewLine,
			TOKEN_OpenBrace,
			TOKEN_CloseBrace,
			TOKEN_EOF,
		};
 
		Token tok, lastTok;
		std::string tokVal, lastTokVal;
 
		void _parseNodes(std::ifstream &stream, ConfigNode *parent);
		void _nextToken(std::ifstream &stream);
		void _skipNewLines(std::ifstream &stream);
 
		virtual void clearScriptList();
	};
 
	class ConfigNode
	{
	public:
		ConfigNode(ConfigNode *parent, const std::string &name = "untitled");
		~ConfigNode();
 
		inline void setName(const std::string &name)
		{
			this->m_name = name;
		}
 
		inline std::string &getName()
		{
			return m_name;
		}
 
		inline void addValue(const std::string &value)
		{
			m_values.push_back(value);
		}
 
		inline void clearValues()
		{
			m_values.clear();
		}
 
		inline std::vector<std::string> &getValues()
		{
			return m_values;
		}
 
		inline const std::string &getValue(unsigned int index = 0)
		{
			assert(index < m_values.size());
			return m_values[index];
		}
 
		ConfigNode *addChild(const std::string &name = "untitled", bool replaceExisting = false);
		ConfigNode *findChild(const std::string &name, bool recursive = false);
 
		inline std::vector<ConfigNode*> &getChildren()
		{
			return m_children;
		}
 
		inline ConfigNode *getChild(unsigned int index = 0)
		{
			assert(index < m_children.size());
			return m_children[index];
		}
 
		void setParent(ConfigNode *newParent);
 
		inline ConfigNode *getParent()
		{
			return m_parent;
		}
 
	private:
		std::string m_name;
		std::vector<std::string> m_values;
		std::vector<ConfigNode*> m_children;
		ConfigNode *m_parent;
 
		int m_lastChildFound;  //The last child node's index found with a call to findChild()
 
		std::vector<ConfigNode*>::iterator _iter;
		bool _removeSelf;
	};
 
}
 
#endif

 

 

//cpp

#include "ConfigLoader.hpp"
 
#include <vector>
#include <map>
#include <exception>
#include <fstream>
 
#include <boost/filesystem.hpp>
 
namespace sh
{
	void ConfigLoader::loadAllFiles(ConfigLoader* c, const std::string& path)
	{
		for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir )
		{
			boost::filesystem::path p(*dir);
			if(p.extension() == c->m_fileEnding)
			{
				std::ifstream in((*dir).path().string().c_str(), std::ios::binary);
				c->parseScript(in);
			}
		}
	}
 
	ConfigLoader::ConfigLoader(const std::string& fileEnding)
	{
		//Register as a ScriptLoader
		m_fileEnding = fileEnding;
	}
 
	ConfigLoader::~ConfigLoader()
	{
		clearScriptList();
 
	}
 
	void ConfigLoader::clearScriptList()
	{
		std::map <std::string, ConfigNode *>::iterator i;
		for (i = m_scriptList.begin(); i != m_scriptList.end(); i++)
		{
			delete i->second;
		}
		m_scriptList.clear();
	}
 
	ConfigNode *ConfigLoader::getConfigScript(const std::string &name)
	{
		std::map <std::string, ConfigNode*>::iterator i;
 
		std::string key = name;
		i = m_scriptList.find(key);
 
		//If found..
		if (i != m_scriptList.end())
		{
			return i->second;
		}
		else
		{
			return NULL;
		}
	}
 
	std::map <std::string, ConfigNode*> ConfigLoader::getAllConfigScripts ()
	{
		return m_scriptList;
	}
 
	void ConfigLoader::parseScript(std::ifstream &stream)
	{
		//Get first token
		_nextToken(stream);
		if (tok == TOKEN_EOF)
		{
			stream.close();
			return;
		}
 
		//Parse the script
		_parseNodes(stream, 0);
 
		stream.close();
	}
 
	void ConfigLoader::_nextToken(std::ifstream &stream)
	{
		lastTok = tok;
		lastTokVal = tokVal;
 
		//EOF token
		if (stream.eof())
		{
			tok = TOKEN_EOF;
			return;
		}
 
		//(Get next character)
		int ch = stream.get();
		if (ch == -1)
		{
			tok = TOKEN_EOF;
			return;
		}
		while ((ch == ' ' || ch == 9) && !stream.eof())
		{    //Skip leading spaces / tabs
			ch = stream.get();
		}
 
		if (stream.eof())
		{
			tok = TOKEN_EOF;
			return;
		}
 
		//Newline token
		if (ch == '\r' || ch == '\n')
		{
			do
			{
				ch = stream.get();
			} while ((ch == '\r' || ch == '\n') && !stream.eof());
 
			stream.unget();
 
			tok = TOKEN_NewLine;
			return;
		}
 
		//Open brace token
		else if (ch == '{')
		{
			tok = TOKEN_OpenBrace;
			return;
		}
 
		//Close brace token
		else if (ch == '}')
		{
			tok = TOKEN_CloseBrace;
			return;
		}
 
		//Text token
		if (ch < 32 || ch > 122)    //Verify valid char
		{
			throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()");
		}
 
		tokVal = "";
		tok = TOKEN_Text;
		do
		{
			//Skip comments
			if (ch == '/')
			{
				int ch2 = stream.peek();
 
				//C++ style comment (//)
				if (ch2 == '/')
				{
					stream.get();
					do
					{
						ch = stream.get();
					} while (ch != '\r' && ch != '\n' && !stream.eof());
 
					tok = TOKEN_NewLine;
					return;
				}
			}
 
			//Add valid char to tokVal
			tokVal += (char)ch;
 
			//Next char
			ch = stream.get();
 
		} while (ch > 32 && ch <= 122 && !stream.eof());
 
		stream.unget();
 
		return;
	}
 
	void ConfigLoader::_skipNewLines(std::ifstream &stream)
	{
		while (tok == TOKEN_NewLine)
		{
			_nextToken(stream);
		}
	}
 
	void ConfigLoader::_parseNodes(std::ifstream &stream, ConfigNode *parent)
	{
		typedef std::pair<std::string, ConfigNode*> ScriptItem;
 
		while (true)
		{
			switch (tok)
			{
				//Node
				case TOKEN_Text:
					//Add the new node
					ConfigNode *newNode;
					if (parent)
					{
						newNode = parent->addChild(tokVal);
					}
					else
					{
						newNode = new ConfigNode(0, tokVal);
					}
 
					//Get values
					_nextToken(stream);
					while (tok == TOKEN_Text)
					{
						newNode->addValue(tokVal);
						_nextToken(stream);
					}
 
					//Add root nodes to scriptList
					if (!parent){
						std::string key;
 
						if (newNode->getValues().empty())
						{
							key = newNode->getName() + ' ';
						}
						else
						{
							key = newNode->getName() + ' ' + newNode->getValues().front();
						}
 
						m_scriptList.insert(ScriptItem(key, newNode));
					}
 
					_skipNewLines(stream);
 
					//Add any sub-nodes
					if (tok == TOKEN_OpenBrace)
					{
						//Parse nodes
						_nextToken(stream);
						_parseNodes(stream, newNode);
						//Check for matching closing brace
						if (tok != TOKEN_CloseBrace)
						{
							throw std::runtime_error("Parse Error: Expecting closing brace");
						}
						_nextToken(stream);
						_skipNewLines(stream);
					}
 
					break;
 
				//Out of place brace
				case TOKEN_OpenBrace:
					throw std::runtime_error("Parse Error: Opening brace out of plane");
					break;
 
				//Return if end of nodes have been reached
				case TOKEN_CloseBrace:
					return;
 
				//Return if reached end of file
				case TOKEN_EOF:
					return;
 
				case TOKEN_NewLine:
					_nextToken(stream);
					break;
			}
		};
	}
 
	ConfigNode::ConfigNode(ConfigNode *parent, const std::string &name)
	{
		m_name = name;
		m_parent = parent;
		_removeSelf = true;    //For proper destruction
		m_lastChildFound = -1;
 
		//Add self to parent's child list (unless this is the root node being created)
		if (parent != NULL)
		{
			m_parent->m_children.push_back(this);
			_iter = --(m_parent->m_children.end());
		}
	}
 
	ConfigNode::~ConfigNode()
	{
		//Delete all children
		std::vector<ConfigNode*>::iterator i;
		for (i = m_children.begin(); i != m_children.end(); i++)
		{
			ConfigNode *node = *i;
			node->_removeSelf = false;
			delete node;
		}
		m_children.clear();
 
		//Remove self from parent's child list
		if (_removeSelf && m_parent != NULL)
		{
			m_parent->m_children.erase(_iter);
		}
	}
 
	ConfigNode *ConfigNode::addChild(const std::string &name, bool replaceExisting)
	{
		if (replaceExisting)
		{
			ConfigNode *node = findChild(name, false);
			if (node)
			{
				return node;
			}
		}
		return new ConfigNode(this, name);
	}
 
	ConfigNode *ConfigNode::findChild(const std::string &name, bool recursive)
	{
		int indx, prevC, nextC;
		int childCount = (int)m_children.size();
 
		if (m_lastChildFound != -1)
		{
			//If possible, try checking the nodes neighboring the last successful search
			//(often nodes searched for in sequence, so this will boost search speeds).
			prevC = m_lastChildFound-1; if (prevC < 0) prevC = 0; else if (prevC >= childCount) prevC = childCount-1;
			nextC = m_lastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-1;
			for (indx = prevC; indx <= nextC; ++indx)
			{
				ConfigNode *node = m_children[indx];
				if (node->m_name == name)
				{
					m_lastChildFound = indx;
					return node;
				}
			}
 
			//If not found that way, search for the node from start to finish, avoiding the
			//already searched area above.
			for (indx = nextC + 1; indx < childCount; ++indx)
			{
				ConfigNode *node = m_children[indx];
				if (node->m_name == name) {
					m_lastChildFound = indx;
					return node;
				}
			}
			for (indx = 0; indx < prevC; ++indx)
			{
				ConfigNode *node = m_children[indx];
				if (node->m_name == name) {
					m_lastChildFound = indx;
					return node;
				}
			}
		}
		else
		{
			//Search for the node from start to finish
			for (indx = 0; indx < childCount; ++indx){
				ConfigNode *node = m_children[indx];
				if (node->m_name == name) {
					m_lastChildFound = indx;
					return node;
				}
			}
		}
 
		//If not found, search child nodes (if recursive == true)
		if (recursive)
		{
			for (indx = 0; indx < childCount; ++indx)
			{
				m_children[indx]->findChild(name, recursive);
			}
		}
 
		//Not found anywhere
		return NULL;
	}
 
	void ConfigNode::setParent(ConfigNode *newParent)
	{
		//Remove self from current parent
		m_parent->m_children.erase(_iter);
 
		//Set new parent
		m_parent = newParent;
 
		//Add self to new parent
		m_parent->m_children.push_back(this);
		_iter = --(m_parent->m_children.end());
	}
}

你可能感兴趣的:(ogre config-style configfile loader)