1 //  XML_Parser.h - an XML file reader
2 //
3 //	Vamos Automotive Simulator
4 //  Copyright (C) 2004 Sam Varner
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 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20 #ifndef _XML_PARSER_H_
21 #define _XML_PARSER_H_
22 
23 #include <string>
24 #include <fstream>
25 #include <vector>
26 
27 namespace Vamos_Media
28 {
29   //** Exception Classes
30   class XML_Exception
31   {
32   protected:
33 	std::string m_file;
34 	int m_line;
35 	std::string m_message;
36   public:
37 	XML_Exception (std::string file, int line = 0, std::string message = "") :
m_file(file)38 	  m_file (file),
39 	  m_line (line),
40 	  m_message (message)
41 	{};
~XML_Exception()42 	virtual ~XML_Exception () {};
43 
44 	virtual std::string message () const;
45   };
46 
47   class No_XML_File : public XML_Exception
48   {
49   public:
No_XML_File(std::string file)50 	No_XML_File (std::string file) : XML_Exception (file) {};
message()51 	std::string message () const
52 	{ return "Can't find the file \"" + m_file + '"'; }
53   };
54 
55   class No_Declaration : public XML_Exception
56   {
57   public:
No_Declaration(std::string file,int line,std::string message)58 	No_Declaration (std::string file, int line, std::string message) :
59 	  XML_Exception (file, line, message) {};
60   };
61 
62   class Bad_Tag_Type : public XML_Exception
63   {
64   public:
Bad_Tag_Type(std::string file,int line,std::string message)65 	Bad_Tag_Type (std::string file, int line, std::string message) :
66 	  XML_Exception (file, line, message) {};
67   };
68 
69   class Tag_Mismatch : public XML_Exception
70   {
71   public:
Tag_Mismatch(std::string file,int line,std::string message)72 	Tag_Mismatch (std::string file, int line, std::string message) :
73 	  XML_Exception (file, line, message) {}
74   };
75 
76   struct XML_Unterminated
77   {
78 	int lines;
79 	std::string text;
80 	bool eof;
81 	char delimiter;
82 
XML_UnterminatedXML_Unterminated83 	XML_Unterminated (int lines_in,
84 					  std::string text_in,
85 					  bool eof_in,
86 					  char delimiter_in) :
87 	  lines (lines_in),
88 	  text (text_in),
89 	  eof (eof_in),
90 	  delimiter (delimiter_in)
91 	{};
92   };
93 
94   struct Unterminated_Tag : public XML_Unterminated
95   {
Unterminated_TagUnterminated_Tag96 	Unterminated_Tag (int lines_in, std::string text_in, bool eof_in)
97 	  : XML_Unterminated (lines_in, text_in, eof_in, '>') {};
98   };
99 
100   struct Unterminated_Attribute : public XML_Unterminated
101   {
Unterminated_AttributeUnterminated_Attribute102 	Unterminated_Attribute (int lines_in, std::string text_in, bool eof_in)
103 	  : XML_Unterminated (lines_in, text_in, eof_in, '"') {};
104   };
105 
106 
107 
108   //** Class XML_Tag
109   class XML_Tag
110   {
111   public:
112 	enum Tag_Type
113 	  {
114 		NONE,
115 		START,
116 		END,
117 		EMPTY,
118 		PROCESSING_INSTRUCTION,
119 		COMMENT
120 	  };
121 
122 	struct Attribute
123 	{
AttributeAttribute124 	  Attribute (std::string name_in, std::string value_in)
125 		: name (name_in), value (value_in) {}
126 	  std::string name;
127 	  std::string value;
128 	};
129 
130 	typedef std::vector <Attribute> Attribute_List;
131 
132   private:
133 	typedef std::string::iterator String_Iterator;
134 
135 	Tag_Type m_type;
136 	int m_lines;
137 	std::vector <Attribute> m_attributes;
138 	std::string m_data;
139 	std::string m_text;
140 	std::string m_label;
141 
142 	// Read everything up to the next '<'.  Return true if '<' was found.
143 	bool read_to_tag_start (std::ifstream& stream);
144 
145 	// Read everything up to the next `>'.  Return true if '>' was found.
146 	bool read_to_tag_end (std::ifstream& stream);
147 
148 	// Determine the type of the tag.
149 	Tag_Type find_tag_type (std::ifstream& stream);
150 
151 	// Determine the tag's label.
152 	std::string find_label (String_Iterator text_start,
153 							String_Iterator text_end);
154 
155 	// Get the next character from the stream.
156 	std::ifstream& get_next_char (std::ifstream& stream, char& ch);
157 
158 	// Parse attributes.
159 	void find_attributes (String_Iterator attr_begin,
160 						  String_Iterator attr_end);
161 
162 	// Throw out characters inside a comment.
163 	void eat_comment (std::ifstream& stream);
164 
165 	bool find_comment_end (std::ifstream& stream);
166 
167 	void skip_spaces (String_Iterator& text_start);
168 
169 	Attribute get_attribute (String_Iterator text_start,
170 							 String_Iterator text_end);
171 	void get_text_boundries (String_Iterator& text_start,
172 							 String_Iterator& text_end);
173 
174   public:
175 	XML_Tag (std::ifstream& stream);
176 
get_type()177 	Tag_Type get_type () const { return m_type; }
get_lines()178 	int get_lines () const { return m_lines; }
get_attributes()179 	const Attribute_List& get_attributes () const { return m_attributes; }
get_data()180 	std::string get_data () const { return m_data; }
get_text()181 	std::string get_text () const { return m_text; }
get_label()182 	std::string get_label () const { return m_label; }
183   };
184 
185   //** XML Tag Path Class
186   class XML_Path
187   {
188     std::string m_path;
189 
190   public:
push(std::string element)191     void push (std::string element) { m_path += '/' + element; }
drop()192     void drop () { m_path = m_path.substr (0, m_path.find_last_of ("/")); }
empty()193     bool empty () const { return m_path.empty (); }
194     bool match (std::string pattern) const;
path()195     std::string path () const { return m_path; }
196     std::string subpath (size_t n) const;
top()197     std::string top () const { return subpath (1); }
198   };
199 
200   //** Parser Class
201   class XML_Parser
202   {
203   public:
204 	XML_Parser ();
205 	virtual ~XML_Parser ();
206 
207 	void read (std::string file);
208 	void error (std::string message);
209 
match(std::string pattern)210     bool match (std::string pattern) const { return m_path.match (pattern); }
path()211     std::string path () const { return m_path.path (); }
label()212     std::string label () const { return m_path.top (); }
213 
214 	// Event handlers overridden by derived classes.
215 	virtual void on_start_tag (const XML_Tag& tag) = 0;
216 	virtual void on_end_tag (const XML_Tag& tag) = 0;
217 	virtual void on_data (std::string data_string) = 0;
218 
219   private:
220     std::string m_file;
221     std::ifstream* mp_stream;
222     int m_line;
223     XML_Path m_path;
224 
225 	void check_declaration ();
226 	void read_document ();
227 	bool run_callbacks (const XML_Tag& tag);
228 	void add_tag (const XML_Tag& tag);
229 	void remove_tag (const XML_Tag& tag);
230 	void handle_unterminated (XML_Unterminated& unterminated);
231   };
232 }
233 
234 #endif // not _XML_PARSER_H_
235