Timings seem to be _really_ right this time.
[scummvm-innocent.git] / common / xmlparser.cpp
blob534007b03dc31da0d7446568c7582c746728a404
1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * $URL$
22 * $Id$
26 #include "common/xmlparser.h"
27 #include "common/util.h"
28 #include "common/archive.h"
29 #include "common/fs.h"
31 namespace Common {
33 bool XMLParser::loadFile(const Common::String &filename) {
34 _stream = SearchMan.createReadStreamForMember(filename);
35 if (!_stream)
36 return false;
38 _fileName = filename;
39 return true;
42 bool XMLParser::loadFile(const FSNode &node) {
43 _stream = node.createReadStream();
44 if (!_stream)
45 return false;
47 _fileName = node.getName();
48 return true;
51 bool XMLParser::loadBuffer(const byte *buffer, uint32 size, bool disposable) {
52 _stream = new MemoryReadStream(buffer, size, disposable);
53 _fileName = "Memory Stream";
54 return true;
57 bool XMLParser::loadStream(Common::SeekableReadStream *stream) {
58 _stream = stream;
59 _fileName = "File Stream";
60 return true;
63 void XMLParser::close() {
64 delete _stream;
65 _stream = 0;
68 bool XMLParser::parserError(const char *errorString, ...) {
69 _state = kParserError;
71 const int startPosition = _stream->pos();
72 int currentPosition = startPosition;
73 int lineCount = 1;
74 char c = 0;
76 _stream->seek(0, SEEK_SET);
78 while (currentPosition--) {
79 c = _stream->readByte();
81 if (c == '\n' || c == '\r')
82 lineCount++;
85 assert(_stream->pos() == startPosition);
86 currentPosition = startPosition;
88 int keyOpening = 0;
89 int keyClosing = 0;
91 while (currentPosition-- && keyOpening == 0) {
92 _stream->seek(-2, SEEK_CUR);
93 c = _stream->readByte();
95 if (c == '<')
96 keyOpening = currentPosition - 1;
97 else if (c == '>')
98 keyClosing = currentPosition;
101 _stream->seek(startPosition, SEEK_SET);
102 currentPosition = startPosition;
103 while (keyClosing == 0 && c && currentPosition++) {
104 c = _stream->readByte();
106 if (c == '>')
107 keyClosing = currentPosition;
110 fprintf(stderr, "\n File <%s>, line %d:\n", _fileName.c_str(), lineCount);
112 currentPosition = (keyClosing - keyOpening);
113 _stream->seek(keyOpening, SEEK_SET);
115 while (currentPosition--)
116 fprintf(stderr, "%c", _stream->readByte());
118 fprintf(stderr, "\n\nParser error: ");
120 va_list args;
121 va_start(args, errorString);
122 vfprintf(stderr, errorString, args);
123 va_end(args);
125 fprintf(stderr, "\n\n");
127 return false;
130 bool XMLParser::parseXMLHeader(ParserNode *node) {
131 assert(node->header);
133 if (_activeKey.size() != 1)
134 return parserError("XML Header is expected in the global scope.");
136 if (!node->values.contains("version"))
137 return parserError("Missing XML version in XML header.");
139 if (node->values["version"] != "1.0")
140 return parserError("Unsupported XML version.");
142 return true;
145 bool XMLParser::parseActiveKey(bool closed) {
146 bool ignore = false;
147 assert(_activeKey.empty() == false);
149 ParserNode *key = _activeKey.top();
151 if (key->name == "xml" && key->header == true) {
152 assert(closed);
153 return parseXMLHeader(key) && closeKey();
156 XMLKeyLayout *layout = (_activeKey.size() == 1) ? _XMLkeys : getParentNode(key)->layout;
158 if (layout->children.contains(key->name)) {
159 key->layout = layout->children[key->name];
161 Common::StringMap localMap = key->values;
162 int keyCount = localMap.size();
164 for (Common::List<XMLKeyLayout::XMLKeyProperty>::const_iterator i = key->layout->properties.begin(); i != key->layout->properties.end(); ++i) {
165 if (i->required && !localMap.contains(i->name))
166 return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str());
167 else if (localMap.contains(i->name))
168 keyCount--;
171 if (keyCount > 0)
172 return parserError("Unhandled property inside key '%s'.", key->name.c_str());
174 } else {
175 return parserError("Unexpected key in the active scope ('%s').", key->name.c_str());
178 // check if any of the parents must be ignored.
179 // if a parent is ignored, all children are too.
180 for (int i = _activeKey.size() - 1; i >= 0; --i) {
181 if (_activeKey[i]->ignore)
182 ignore = true;
185 if (ignore == false && keyCallback(key) == false) {
186 // HACK: People may be stupid and overlook the fact that
187 // when keyCallback() fails, a parserError() must be set.
188 // We set it manually in that case.
189 if (_state != kParserError)
190 parserError("Unhandled exception when parsing '%s' key.", key->name.c_str());
192 return false;
195 if (closed)
196 return closeKey();
198 return true;
201 bool XMLParser::parseKeyValue(Common::String keyName) {
202 assert(_activeKey.empty() == false);
204 if (_activeKey.top()->values.contains(keyName))
205 return false;
207 _token.clear();
208 char stringStart;
210 if (_char == '"' || _char == '\'') {
211 stringStart = _char;
212 _char = _stream->readByte();
214 while (_char && _char != stringStart) {
215 _token += _char;
216 _char = _stream->readByte();
219 if (_char == 0)
220 return false;
222 _char = _stream->readByte();
224 } else if (!parseToken()) {
225 return false;
228 _activeKey.top()->values[keyName] = _token;
229 return true;
232 bool XMLParser::closeKey() {
233 bool ignore = false;
234 bool result = true;
236 for (int i = _activeKey.size() - 1; i >= 0; --i) {
237 if (_activeKey[i]->ignore)
238 ignore = true;
241 if (ignore == false)
242 result = closedKeyCallback(_activeKey.top());
244 freeNode(_activeKey.pop());
246 return result;
249 bool XMLParser::parse() {
251 if (_stream == 0)
252 return parserError("XML stream not ready for reading.");
254 if (_XMLkeys == 0)
255 buildLayout();
257 while (!_activeKey.empty())
258 freeNode(_activeKey.pop());
260 cleanup();
262 bool activeClosure = false;
263 bool activeHeader = false;
264 bool selfClosure;
266 _state = kParserNeedHeader;
267 _activeKey.clear();
269 _char = _stream->readByte();
271 while (_char && _state != kParserError) {
272 if (skipSpaces())
273 continue;
275 if (skipComments())
276 continue;
278 switch (_state) {
279 case kParserNeedHeader:
280 case kParserNeedKey:
281 if (_char != '<') {
282 parserError("Parser expecting key start.");
283 break;
286 if ((_char = _stream->readByte()) == 0) {
287 parserError("Unexpected end of file.");
288 break;
291 if (_state == kParserNeedHeader) {
292 if (_char != '?') {
293 parserError("Expecting XML header.");
294 break;
297 _char = _stream->readByte();
298 activeHeader = true;
299 } else if (_char == '/') {
300 _char = _stream->readByte();
301 activeClosure = true;
302 } else if (_char == '?') {
303 parserError("Unexpected header. There may only be one XML header per file.");
304 break;
307 _state = kParserNeedKeyName;
308 break;
310 case kParserNeedKeyName:
311 if (!parseToken()) {
312 parserError("Invalid key name.");
313 break;
316 if (activeClosure) {
317 if (_activeKey.empty() || _token != _activeKey.top()->name) {
318 parserError("Unexpected closure.");
319 break;
321 } else {
322 ParserNode *node = allocNode(); //new ParserNode;
323 node->name = _token;
324 node->ignore = false;
325 node->header = activeHeader;
326 node->depth = _activeKey.size();
327 node->layout = 0;
328 _activeKey.push(node);
331 _state = kParserNeedPropertyName;
332 break;
334 case kParserNeedPropertyName:
335 if (activeClosure) {
336 if (!closeKey()) {
337 parserError("Missing data when closing key '%s'.", _activeKey.top()->name.c_str());
338 break;
341 activeClosure = false;
343 if (_char != '>')
344 parserError("Invalid syntax in key closure.");
345 else
346 _state = kParserNeedKey;
348 _char = _stream->readByte();
349 break;
352 selfClosure = false;
354 if (_char == '/' || (_char == '?' && activeHeader)) {
355 selfClosure = true;
356 _char = _stream->readByte();
359 if (_char == '>') {
360 if (activeHeader && !selfClosure) {
361 parserError("XML Header must be self-closed.");
362 } else if (parseActiveKey(selfClosure)) {
363 _char = _stream->readByte();
364 _state = kParserNeedKey;
367 activeHeader = false;
368 break;
371 if (selfClosure)
372 parserError("Expecting key closure after '/' symbol.");
373 else if (!parseToken())
374 parserError("Error when parsing key value.");
375 else
376 _state = kParserNeedPropertyOperator;
378 break;
380 case kParserNeedPropertyOperator:
381 if (_char != '=')
382 parserError("Syntax error after key name.");
383 else
384 _state = kParserNeedPropertyValue;
386 _char = _stream->readByte();
387 break;
389 case kParserNeedPropertyValue:
390 if (!parseKeyValue(_token))
391 parserError("Invalid key value.");
392 else
393 _state = kParserNeedPropertyName;
395 break;
397 default:
398 break;
402 if (_state == kParserError)
403 return false;
405 if (_state != kParserNeedKey || !_activeKey.empty())
406 return parserError("Unexpected end of file.");
408 return true;