XMLParser:
- Bug fixes. ThemeParser: - Support for palette colors. - Expanded theme syntax. svn-id: r32787
This commit is contained in:
parent
2fcbb97005
commit
917b750839
4 changed files with 116 additions and 27 deletions
|
@ -36,14 +36,18 @@ using namespace Graphics;
|
||||||
|
|
||||||
void XMLParser::debug_testEval() {
|
void XMLParser::debug_testEval() {
|
||||||
static const char *debugConfigText =
|
static const char *debugConfigText =
|
||||||
"</* lol this is just assa moronic test */drawdata id = \"mainmenu_bg\" cache = true>\n"
|
"<render_info>\n"
|
||||||
"<drawstep func = \"roundedsq\" fill = \"none\" color = \"0, 1, 2\" size = \"auto\" />\n"
|
"<palette>\n"
|
||||||
"<drawstep func = \"roundedsqXD\" fill = \"none\" color = \"0, 1, 2\" size = \"auto\"/>\n"
|
"<color name = \"red\" rgb = \"255, 255, 255\"/>\n"
|
||||||
|
"</palette>\n"
|
||||||
|
"<drawdata id = \"mainmenu_bg\" cache = true>\n"
|
||||||
|
"<drawstep func = \"roundedsq\" radius = 23 fill = \"none\" color = \"0, 1, 2\" size = \"auto\" />\n"
|
||||||
|
"<drawstep func = \"roundedsq\" radius = 15 fill = \"none\" color = \"red\" size = \"auto\"/>\n"
|
||||||
"</drawdata>/* lol this is just a simple test*/\n"
|
"</drawdata>/* lol this is just a simple test*/\n"
|
||||||
"I loled";
|
"</render_info>";
|
||||||
|
|
||||||
loadBuffer(debugConfigText);
|
loadBuffer(debugConfigText);
|
||||||
_fileName = strdup("test_parse.xml");
|
_fileName = "test_parse.xml";
|
||||||
|
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
@ -54,13 +58,13 @@ bool XMLParser::parserError(const char *errorString, ...) {
|
||||||
|
|
||||||
int pos = _pos;
|
int pos = _pos;
|
||||||
int lineCount = 1;
|
int lineCount = 1;
|
||||||
int lineStart = -1;
|
int lineStart = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (_text[pos] == '\n' || _text[pos] == '\r') {
|
if (_text[pos] == '\n' || _text[pos] == '\r') {
|
||||||
lineCount++;
|
lineCount++;
|
||||||
|
|
||||||
if (lineStart == -1)
|
if (lineStart == 0)
|
||||||
lineStart = MAX(pos + 1, _pos - 60);
|
lineStart = MAX(pos + 1, _pos - 60);
|
||||||
}
|
}
|
||||||
} while (pos-- > 0);
|
} while (pos-- > 0);
|
||||||
|
@ -69,14 +73,17 @@ bool XMLParser::parserError(const char *errorString, ...) {
|
||||||
_text.stream()->seek(lineStart, SEEK_SET);
|
_text.stream()->seek(lineStart, SEEK_SET);
|
||||||
_text.stream()->readLine(lineStr, 70);
|
_text.stream()->readLine(lineStr, 70);
|
||||||
|
|
||||||
printf(" File <%s>, line %d:\n", _fileName, lineCount);
|
printf(" File <%s>, line %d:\n", _fileName.c_str(), lineCount);
|
||||||
|
|
||||||
printf("%s%s%s\n",
|
bool startFull = lineStr[0] == '<';
|
||||||
lineStr[0] == '<' ? "" : "...",
|
bool endFull = lineStr[strlen(lineStr) - 1] == '>';
|
||||||
lineStr[strlen(lineStr) - 1] == '>' ? "" : "...",
|
|
||||||
lineStr);
|
|
||||||
|
|
||||||
for (int i = 0; i < _pos - lineStart + 3; ++i)
|
printf("%s%s%s\n", startFull ? "" : "...", endFull ? "" : "...", lineStr);
|
||||||
|
|
||||||
|
if (!startFull)
|
||||||
|
lineStart -= 3;
|
||||||
|
|
||||||
|
for (int i = 0; i < _pos - lineStart; ++i)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
|
|
||||||
printf("^\n");
|
printf("^\n");
|
||||||
|
@ -185,12 +192,15 @@ bool XMLParser::parse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeClosure) {
|
if (activeClosure) {
|
||||||
if (_activeKey.empty() || _token != _activeKey.top()->name)
|
if (_activeKey.empty() || _token != _activeKey.top()->name) {
|
||||||
parserError("Unexpected closure.");
|
parserError("Unexpected closure.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ParserNode *node = new ParserNode;
|
ParserNode *node = new ParserNode;
|
||||||
node->name = _token;
|
node->name = _token;
|
||||||
node->ignore = false;
|
node->ignore = false;
|
||||||
|
node->depth = _activeKey.size();
|
||||||
_activeKey.push(node);
|
_activeKey.push(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ public:
|
||||||
Common::String name;
|
Common::String name;
|
||||||
Common::StringMap values;
|
Common::StringMap values;
|
||||||
bool ignore;
|
bool ignore;
|
||||||
|
int depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual bool loadFile(const char *filename) {
|
virtual bool loadFile(const char *filename) {
|
||||||
|
@ -137,13 +138,20 @@ public:
|
||||||
* Returns the active node being parsed (the one on top of
|
* Returns the active node being parsed (the one on top of
|
||||||
* the node stack).
|
* the node stack).
|
||||||
*/
|
*/
|
||||||
ParserNode *activeNode() {
|
ParserNode *getActiveNode() {
|
||||||
if (!_activeKey.empty())
|
if (!_activeKey.empty())
|
||||||
return _activeKey.top();
|
return _activeKey.top();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parent of a given node in the stack.
|
||||||
|
*/
|
||||||
|
ParserNode *getParentNode(ParserNode *child) {
|
||||||
|
return child->depth > 0 ? _activeKey[child->depth - 1] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* The keycallback function must be overloaded by inheriting classes
|
* The keycallback function must be overloaded by inheriting classes
|
||||||
|
@ -255,7 +263,7 @@ protected:
|
||||||
|
|
||||||
int _pos; /** Current position on the XML buffer. */
|
int _pos; /** Current position on the XML buffer. */
|
||||||
XMLStream _text; /** Buffer with the text being parsed */
|
XMLStream _text; /** Buffer with the text being parsed */
|
||||||
char *_fileName;
|
Common::String _fileName;
|
||||||
|
|
||||||
ParserState _state; /** Internal state of the parser */
|
ParserState _state; /** Internal state of the parser */
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ using namespace Common;
|
||||||
ThemeParser::ThemeParser() : XMLParser() {
|
ThemeParser::ThemeParser() : XMLParser() {
|
||||||
_callbacks["drawstep"] = &ThemeParser::parserCallback_DRAWSTEP;
|
_callbacks["drawstep"] = &ThemeParser::parserCallback_DRAWSTEP;
|
||||||
_callbacks["drawdata"] = &ThemeParser::parserCallback_DRAWDATA;
|
_callbacks["drawdata"] = &ThemeParser::parserCallback_DRAWDATA;
|
||||||
|
_callbacks["palette"] = &ThemeParser::parserCallback_palette;
|
||||||
|
_callbacks["color"] = &ThemeParser::parserCallback_color;
|
||||||
|
_callbacks["render_info"] = &ThemeParser::parserCallback_renderInfo;
|
||||||
|
|
||||||
_drawFunctions["circle"] = &Graphics::VectorRenderer::drawCallback_CIRCLE;
|
_drawFunctions["circle"] = &Graphics::VectorRenderer::drawCallback_CIRCLE;
|
||||||
_drawFunctions["square"] = &Graphics::VectorRenderer::drawCallback_SQUARE;
|
_drawFunctions["square"] = &Graphics::VectorRenderer::drawCallback_SQUARE;
|
||||||
|
@ -81,20 +84,69 @@ Graphics::DrawStep *ThemeParser::newDrawStep() {
|
||||||
return step;
|
return step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ThemeParser::parserCallback_renderInfo() {
|
||||||
|
ParserNode *infoNode = getActiveNode();
|
||||||
|
|
||||||
|
assert(infoNode->name == "render_info");
|
||||||
|
|
||||||
|
if (getParentNode(infoNode) != 0)
|
||||||
|
return parserError("<render_info> keys must be root elements.");
|
||||||
|
|
||||||
|
// TODO: Skip key if it's not for this platform.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThemeParser::parserCallback_palette() {
|
||||||
|
ParserNode *paletteNode = getActiveNode();
|
||||||
|
|
||||||
|
assert(paletteNode->name == "palette");
|
||||||
|
|
||||||
|
if (getParentNode(paletteNode) == 0 || getParentNode(paletteNode)->name != "render_info")
|
||||||
|
return parserError("Palette keys must be contained inside a <render_info> section.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThemeParser::parserCallback_color() {
|
||||||
|
ParserNode *colorNode = getActiveNode();
|
||||||
|
|
||||||
|
if (getParentNode(colorNode) == 0 || getParentNode(colorNode)->name != "palette")
|
||||||
|
return parserError("Colors must be specified inside <palette> tags.");
|
||||||
|
|
||||||
|
if (!colorNode->values.contains("name") || !colorNode->values.contains("rgb"))
|
||||||
|
return parserError("Color keys must contain 'name' and 'rgb' values for the color.");
|
||||||
|
|
||||||
|
Common::String name = colorNode->values["name"];
|
||||||
|
|
||||||
|
if (_palette.contains(name))
|
||||||
|
return parserError("Color '%s' has already been defined.", name.c_str());
|
||||||
|
|
||||||
|
int red, green, blue;
|
||||||
|
|
||||||
|
if (sscanf(colorNode->values["rgb"].c_str(), "%d, %d, %d", &red, &green, &blue) != 3 ||
|
||||||
|
red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255)
|
||||||
|
return parserError("Error when parsing RGB values for palette color '%s'", name.c_str());\
|
||||||
|
|
||||||
|
_palette[name].r = red;
|
||||||
|
_palette[name].g = green;
|
||||||
|
_palette[name].b = blue;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ThemeParser::parserCallback_DRAWSTEP() {
|
bool ThemeParser::parserCallback_DRAWSTEP() {
|
||||||
ParserNode *stepNode = _activeKey.top();
|
ParserNode *stepNode = _activeKey.top();
|
||||||
|
ParserNode *drawdataNode = getParentNode(stepNode);
|
||||||
|
|
||||||
// HACK: Any cleaner way to access the second item from
|
if (!drawdataNode || drawdataNode->name != "drawdata")
|
||||||
// the top without popping? Let's keep it this way and hope
|
return parserError("DrawStep keys must be located inside a DrawData set.");
|
||||||
// the internal representation doesn't change
|
|
||||||
ParserNode *drawdataNode = _activeKey[_activeKey.size() - 2];
|
|
||||||
|
|
||||||
assert(stepNode->name == "drawstep");
|
assert(stepNode->name == "drawstep");
|
||||||
assert(drawdataNode->name == "drawdata");
|
|
||||||
assert(drawdataNode->values.contains("id"));
|
assert(drawdataNode->values.contains("id"));
|
||||||
|
|
||||||
Graphics::DrawStep *drawstep = newDrawStep();
|
Graphics::DrawStep *drawstep = newDrawStep();
|
||||||
|
|
||||||
Common::String functionName = stepNode->values["func"];
|
Common::String functionName = stepNode->values["func"];
|
||||||
|
|
||||||
if (_drawFunctions.contains(functionName) == false)
|
if (_drawFunctions.contains(functionName) == false)
|
||||||
|
@ -102,7 +154,7 @@ bool ThemeParser::parserCallback_DRAWSTEP() {
|
||||||
|
|
||||||
drawstep->drawingCall = _drawFunctions[functionName];
|
drawstep->drawingCall = _drawFunctions[functionName];
|
||||||
|
|
||||||
uint32 red, green, blue, w, h;
|
int red, green, blue, w, h;
|
||||||
Common::String val;
|
Common::String val;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,9 +190,14 @@ bool ThemeParser::parserCallback_DRAWSTEP() {
|
||||||
*/
|
*/
|
||||||
#define __PARSER_ASSIGN_RGB(struct_name, key_name) \
|
#define __PARSER_ASSIGN_RGB(struct_name, key_name) \
|
||||||
if (stepNode->values.contains(key_name)) { \
|
if (stepNode->values.contains(key_name)) { \
|
||||||
if (sscanf(stepNode->values[key_name].c_str(), "%d, %d, %d", &red, &green, &blue) != 3 || \
|
val = stepNode->values[key_name]; \
|
||||||
|
if (_palette.contains(val)) { \
|
||||||
|
red = _palette[val].r; \
|
||||||
|
green = _palette[val].g; \
|
||||||
|
blue = _palette[val].b; \
|
||||||
|
} else if (sscanf(val.c_str(), "%d, %d, %d", &red, &green, &blue) != 3 || \
|
||||||
red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) \
|
red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) \
|
||||||
return parserError("Error when parsing color struct '%s'", stepNode->values[key_name].c_str());\
|
return parserError("Error when parsing color struct '%s'", val.c_str());\
|
||||||
\
|
\
|
||||||
drawstep->struct_name.r = red; \
|
drawstep->struct_name.r = red; \
|
||||||
drawstep->struct_name.g = green; \
|
drawstep->struct_name.g = green; \
|
||||||
|
@ -221,8 +278,13 @@ bool ThemeParser::parserCallback_DRAWDATA() {
|
||||||
ParserNode *drawdataNode = _activeKey.top();
|
ParserNode *drawdataNode = _activeKey.top();
|
||||||
bool cached = false;
|
bool cached = false;
|
||||||
|
|
||||||
|
assert(drawdataNode->name == "drawdata");
|
||||||
|
|
||||||
|
if (getParentNode(drawdataNode) == 0 || getParentNode(drawdataNode)->name != "render_info")
|
||||||
|
return parserError("DrawData keys must be contained inside a <render_info> section.");
|
||||||
|
|
||||||
if (drawdataNode->values.contains("id") == false)
|
if (drawdataNode->values.contains("id") == false)
|
||||||
return parserError("DrawData notes must contain an identifier.");
|
return parserError("DrawData keys must contain an identifier.");
|
||||||
|
|
||||||
InterfaceManager::DrawData id = g_InterfaceManager.getDrawDataId(drawdataNode->values["id"]);
|
InterfaceManager::DrawData id = g_InterfaceManager.getDrawDataId(drawdataNode->values["id"]);
|
||||||
|
|
||||||
|
|
|
@ -320,6 +320,9 @@ protected:
|
||||||
|
|
||||||
bool parserCallback_DRAWSTEP();
|
bool parserCallback_DRAWSTEP();
|
||||||
bool parserCallback_DRAWDATA();
|
bool parserCallback_DRAWDATA();
|
||||||
|
bool parserCallback_palette();
|
||||||
|
bool parserCallback_color();
|
||||||
|
bool parserCallback_renderInfo();
|
||||||
|
|
||||||
bool validateKeyIntSigned(const char *key) {
|
bool validateKeyIntSigned(const char *key) {
|
||||||
if (!isdigit(*key) && *key != '+' && *key != '-')
|
if (!isdigit(*key) && *key != '+' && *key != '-')
|
||||||
|
@ -343,6 +346,12 @@ protected:
|
||||||
|
|
||||||
Common::HashMap<Common::String, DrawingFunctionCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _drawFunctions;
|
Common::HashMap<Common::String, DrawingFunctionCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _drawFunctions;
|
||||||
Common::HashMap<Common::String, ParserCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _callbacks;
|
Common::HashMap<Common::String, ParserCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _callbacks;
|
||||||
|
|
||||||
|
struct PaletteColor {
|
||||||
|
uint8 r, g, b;
|
||||||
|
};
|
||||||
|
|
||||||
|
Common::HashMap<Common::String, PaletteColor, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _palette;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue