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.
26 #include "common/xmlparser.h"
27 #include "common/util.h"
28 #include "common/archive.h"
29 #include "common/fs.h"
33 bool XMLParser::loadFile(const Common::String
&filename
) {
34 _stream
= SearchMan
.createReadStreamForMember(filename
);
42 bool XMLParser::loadFile(const FSNode
&node
) {
43 _stream
= node
.createReadStream();
47 _fileName
= node
.getName();
51 bool XMLParser::loadBuffer(const byte
*buffer
, uint32 size
, bool disposable
) {
52 _stream
= new MemoryReadStream(buffer
, size
, disposable
);
53 _fileName
= "Memory Stream";
57 bool XMLParser::loadStream(Common::SeekableReadStream
*stream
) {
59 _fileName
= "File Stream";
63 void XMLParser::close() {
68 bool XMLParser::parserError(const char *errorString
, ...) {
69 _state
= kParserError
;
71 const int startPosition
= _stream
->pos();
72 int currentPosition
= startPosition
;
76 _stream
->seek(0, SEEK_SET
);
78 while (currentPosition
--) {
79 c
= _stream
->readByte();
81 if (c
== '\n' || c
== '\r')
85 assert(_stream
->pos() == startPosition
);
86 currentPosition
= startPosition
;
91 while (currentPosition
-- && keyOpening
== 0) {
92 _stream
->seek(-2, SEEK_CUR
);
93 c
= _stream
->readByte();
96 keyOpening
= currentPosition
- 1;
98 keyClosing
= currentPosition
;
101 _stream
->seek(startPosition
, SEEK_SET
);
102 currentPosition
= startPosition
;
103 while (keyClosing
== 0 && c
&& currentPosition
++) {
104 c
= _stream
->readByte();
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: ");
121 va_start(args
, errorString
);
122 vfprintf(stderr
, errorString
, args
);
125 fprintf(stderr
, "\n\n");
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.");
145 bool XMLParser::parseActiveKey(bool closed
) {
147 assert(_activeKey
.empty() == false);
149 ParserNode
*key
= _activeKey
.top();
151 if (key
->name
== "xml" && key
->header
== true) {
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
))
172 return parserError("Unhandled property inside key '%s'.", key
->name
.c_str());
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
)
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());
201 bool XMLParser::parseKeyValue(Common::String keyName
) {
202 assert(_activeKey
.empty() == false);
204 if (_activeKey
.top()->values
.contains(keyName
))
210 if (_char
== '"' || _char
== '\'') {
212 _char
= _stream
->readByte();
214 while (_char
&& _char
!= stringStart
) {
216 _char
= _stream
->readByte();
222 _char
= _stream
->readByte();
224 } else if (!parseToken()) {
228 _activeKey
.top()->values
[keyName
] = _token
;
232 bool XMLParser::closeKey() {
236 for (int i
= _activeKey
.size() - 1; i
>= 0; --i
) {
237 if (_activeKey
[i
]->ignore
)
242 result
= closedKeyCallback(_activeKey
.top());
244 freeNode(_activeKey
.pop());
249 bool XMLParser::parse() {
252 return parserError("XML stream not ready for reading.");
257 while (!_activeKey
.empty())
258 freeNode(_activeKey
.pop());
262 bool activeClosure
= false;
263 bool activeHeader
= false;
266 _state
= kParserNeedHeader
;
269 _char
= _stream
->readByte();
271 while (_char
&& _state
!= kParserError
) {
279 case kParserNeedHeader
:
282 parserError("Parser expecting key start.");
286 if ((_char
= _stream
->readByte()) == 0) {
287 parserError("Unexpected end of file.");
291 if (_state
== kParserNeedHeader
) {
293 parserError("Expecting XML header.");
297 _char
= _stream
->readByte();
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.");
307 _state
= kParserNeedKeyName
;
310 case kParserNeedKeyName
:
312 parserError("Invalid key name.");
317 if (_activeKey
.empty() || _token
!= _activeKey
.top()->name
) {
318 parserError("Unexpected closure.");
322 ParserNode
*node
= allocNode(); //new ParserNode;
324 node
->ignore
= false;
325 node
->header
= activeHeader
;
326 node
->depth
= _activeKey
.size();
328 _activeKey
.push(node
);
331 _state
= kParserNeedPropertyName
;
334 case kParserNeedPropertyName
:
337 parserError("Missing data when closing key '%s'.", _activeKey
.top()->name
.c_str());
341 activeClosure
= false;
344 parserError("Invalid syntax in key closure.");
346 _state
= kParserNeedKey
;
348 _char
= _stream
->readByte();
354 if (_char
== '/' || (_char
== '?' && activeHeader
)) {
356 _char
= _stream
->readByte();
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;
372 parserError("Expecting key closure after '/' symbol.");
373 else if (!parseToken())
374 parserError("Error when parsing key value.");
376 _state
= kParserNeedPropertyOperator
;
380 case kParserNeedPropertyOperator
:
382 parserError("Syntax error after key name.");
384 _state
= kParserNeedPropertyValue
;
386 _char
= _stream
->readByte();
389 case kParserNeedPropertyValue
:
390 if (!parseKeyValue(_token
))
391 parserError("Invalid key value.");
393 _state
= kParserNeedPropertyName
;
402 if (_state
== kParserError
)
405 if (_state
!= kParserNeedKey
|| !_activeKey
.empty())
406 return parserError("Unexpected end of file.");