aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti2008-06-24 19:48:01 +0000
committerVicent Marti2008-06-24 19:48:01 +0000
commit8caa7d3f8b1146fafc6dff6de4f801eb2e8b61ae (patch)
tree896c10a542fd3c4169ac8c0d218552f84834a02b
parenta4b4534a66bb6f24a66a27e28f7df0d390e1eea8 (diff)
downloadscummvm-rg350-8caa7d3f8b1146fafc6dff6de4f801eb2e8b61ae.tar.gz
scummvm-rg350-8caa7d3f8b1146fafc6dff6de4f801eb2e8b61ae.tar.bz2
scummvm-rg350-8caa7d3f8b1146fafc6dff6de4f801eb2e8b61ae.zip
Common:
- Added function to get the active host type as a string. XMLParser: - Added support for ignoring keys while parsing (check documentation). Backwards compatible. - parserError() has been revamped. Shows all kinds of detailed information regarding the error ala Python InterfaceManager/ThemeParser: - DrawData keys and their DrawStep subkeys are now successfully parsed and loaded into structs. That's a win. - Bug fixes. svn-id: r32768
-rw-r--r--common/util.cpp29
-rw-r--r--common/util.h7
-rw-r--r--common/xmlparser.cpp85
-rw-r--r--common/xmlparser.h17
-rw-r--r--gui/InterfaceManager.cpp51
-rw-r--r--gui/InterfaceManager.h9
-rw-r--r--gui/ThemeParser.cpp111
-rw-r--r--gui/ThemeParser.h18
8 files changed, 293 insertions, 34 deletions
diff --git a/common/util.cpp b/common/util.cpp
index 6f0fdcb233..51bd8bcad6 100644
--- a/common/util.cpp
+++ b/common/util.cpp
@@ -481,6 +481,34 @@ uint32 getEnabledSpecialDebugLevels() {
return gDebugLevelsEnabled;
}
+const char *getHostPlatformString() {
+
+#if defined(__SYMBIAN32__)
+ return "symbian";
+#elif defined(_WIN32_WCE) || defined(_MSC_VER) || defined(__MINGW32__) || defined(UNIX)
+ return "pc";
+#elif defined(__PALMOS_TRAPS__) || defined (__PALMOS_ARMLET__)
+ return "palmos";
+#elif defined(__DC__)
+ return "dc";
+#elif defined(__GP32__)
+ return "gp32";
+#elif defined(__PLAYSTATION2__)
+ return "ps2";
+#elif defined(__PSP__)
+ return "psp";
+#elif defined(__amigaos4__)
+ return "amigaos";
+#elif defined (__DS__) //NeilM
+ return "nds";
+#elif defined(__WII__)
+ return "wii";
+#else
+ return "";
+#endif
+
+}
+
} // End of namespace Common
@@ -694,3 +722,4 @@ Common::String tag2string(uint32 tag) {
str[4] = '\0';
return Common::String(str);
}
+
diff --git a/common/util.h b/common/util.h
index c23513596c..c4cbf35212 100644
--- a/common/util.h
+++ b/common/util.h
@@ -323,6 +323,13 @@ const DebugLevelContainer &listSpecialDebugLevels();
uint32 getEnabledSpecialDebugLevels();
+/**
+ * Return a string containing the name of the currently running host.
+ * E.g. returns "wii" if ScummVM is being run in a Wii, and so on.
+ */
+const char *getHostPlatformString();
+
+
} // End of namespace Common
diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp
index 7728d90d48..de10269cdb 100644
--- a/common/xmlparser.cpp
+++ b/common/xmlparser.cpp
@@ -36,35 +36,86 @@ using namespace Graphics;
void XMLParser::debug_testEval() {
static const char *debugConfigText =
- "</* lol this is just a moronic test */drawdata id = \"background_default\" cache = true>\n"
- "<drawstep func = \"roundedsq\" fill = \"gradient\" gradient_start = \"255, 255, 128\" gradient_end = \"128, 128, 128\" size = \"auto\"/>\n"
+ "</* lol this is just a moronic test */drawdata id = \"mainmenu_bg\" cache = true>\n"
+ "<drawstep| func = \"roundedsq\" fill = \"gradient\" gradient_start = \"255, 255, 128\" gradient_end = \"128, 128, 128\" size = \"auto\"/>\n"
"//<drawstep func = \"roundedsq\" fill = \"none\" color = /*\"0, 0, 0\"*/\"0, 1, 2\" size = \"auto\"/>\n"
"</ drawdata>/* lol this is just a simple test*/\n";
_text = strdup(debugConfigText);
+ _fileName = strdup("test_parse.xml");
Common::String test = "12, 125, 125";
- printf("\n\nRegex result: %s.\n\n", test.regexMatch("^[d]*,[d]*,[d]*$", true) ? "Success." : "Fail");
-
parse();
}
-void XMLParser::parserError(const char *error_string) {
+void XMLParser::parserError(const char *error_string, ...) {
_state = kParserError;
- printf("PARSER ERROR: %s\n", error_string);
+
+ int pos = _pos;
+ int line_count = 1;
+ int line_start = -1;
+ int line_width = 1;
+
+ do {
+ if (_text[pos] == '\n' || _text[pos] == '\r') {
+ line_count++;
+
+ if (line_start == -1)
+ line_start = pos;
+ }
+ } while (pos-- > 0);
+
+ line_start = MAX(line_start, _pos - 80);
+
+ do {
+ if (_text[line_start + line_width] == '\n' || _text[line_start + line_width] == '\r')
+ break;
+ } while (_text[line_start + line_width++]);
+
+ line_width = MIN(line_width, 80);
+
+ char linestr[81];
+ strncpy(linestr, &_text[line_start] + 1, line_width );
+ linestr[line_width - 1] = 0;
+
+ printf(" File <%s>, line %d:\n", _fileName, line_count);
+
+ printf("%s\n", linestr);
+ for (int i = 1; i < _pos - line_start; ++i)
+ printf(" ");
+
+ printf("^\n");
+ printf("Parser error: ");
+
+ va_list args;
+ va_start(args, error_string);
+ vprintf(error_string, args);
+ va_end(args);
+
+ printf("\n");
}
-void XMLParser::parseActiveKey(bool closed) {
- if (keyCallback(_activeKey.top()->name) == false) {
- parserError("Unhandled value inside key.");
- return;
+bool XMLParser::parseActiveKey(bool closed) {
+ bool ignore = false;
+
+ // check if any of the parents must be ignored.
+ // if a parent is ignored, all children are too.
+ for (int i = _activeKey.size() - 1; i >= 0; --i) {
+ if (_activeKey[i]->ignore)
+ ignore = true;
+ }
+
+ if (ignore == false && keyCallback(_activeKey.top()->name) == false) {
+ return false;
}
if (closed) {
delete _activeKey.pop();
}
+
+ return true;
}
bool XMLParser::parseKeyValue(Common::String keyName) {
@@ -115,7 +166,7 @@ bool XMLParser::parse() {
switch (_state) {
case kParserNeedKey:
if (_text[_pos++] != '<') {
- parserError("Expecting key start.");
+ parserError("Parser expecting key start.");
break;
}
@@ -144,6 +195,7 @@ bool XMLParser::parse() {
} else {
ParserNode *node = new ParserNode;
node->name = _token;
+ node->ignore = false;
_activeKey.push(node);
}
@@ -166,9 +218,10 @@ bool XMLParser::parse() {
selfClosure = (_text[_pos] == '/');
if ((selfClosure && _text[_pos + 1] == '>') || _text[_pos] == '>') {
- parseActiveKey(selfClosure);
- _pos += selfClosure ? 2 : 1;
- _state = kParserNeedKey;
+ if (parseActiveKey(selfClosure)) {
+ _pos += selfClosure ? 2 : 1;
+ _state = kParserNeedKey;
+ }
break;
}
@@ -181,7 +234,7 @@ bool XMLParser::parse() {
case kParserNeedPropertyOperator:
if (_text[_pos++] != '=')
- parserError("Unexpected character after key name.");
+ parserError("Syntax error after key name.");
else
_state = kParserNeedPropertyValue;
@@ -189,7 +242,7 @@ bool XMLParser::parse() {
case kParserNeedPropertyValue:
if (!parseKeyValue(_token))
- parserError("Unable to parse key value.");
+ parserError("Invalid key value.");
else
_state = kParserNeedPropertyName;
diff --git a/common/xmlparser.h b/common/xmlparser.h
index 3edc2b31e1..c7f7218857 100644
--- a/common/xmlparser.h
+++ b/common/xmlparser.h
@@ -74,6 +74,7 @@ public:
struct ParserNode {
Common::String name;
Common::StringMap values;
+ bool ignore;
};
virtual bool parse();
@@ -103,7 +104,13 @@ protected:
* Remember to leave the node stack _UNCHANGED_ in your own function. Removal
* of closed keys is done automatically.
*
- * Return true if the key was properly handled. False otherwise.
+ * When parsing a key, one may chose to skip it, e.g. because it's not needed
+ * on the current configuration. In order to ignore a key, you must set
+ * the "ignore" field of its KeyNode struct to "true": The key and all its children
+ * will then be automatically ignored by the parser.
+ *
+ * Return true if the key was properly handled (this includes the case when the
+ * key is being ignored). False otherwise.
* See the sample implementation in GUI::ThemeParser.
*/
virtual bool keyCallback(Common::String keyName) {
@@ -120,13 +127,12 @@ protected:
* node stack and calls the keyCallback.
* There's no reason to overload this.
*/
- virtual void parseActiveKey(bool closed);
+ virtual bool parseActiveKey(bool closed);
/**
* Prints an error message when parsing fails and stops the parser.
- * TODO: More descriptive error messages.
*/
- virtual void parserError(const char *errorString);
+ virtual void parserError(const char *errorString, ...);
/**
* Skips spaces/whitelines etc. Returns true if any spaces were skipped.
@@ -163,7 +169,7 @@ protected:
if (_text[_pos] == '/' && _text[_pos + 1] == '/') {
_pos += 2;
- while (_text[_pos] && _text[_pos] != '\n')
+ while (_text[_pos] && _text[_pos] != '\n' && _text[_pos] != '\r')
_pos++;
return true;
}
@@ -194,6 +200,7 @@ protected:
int _pos; /** Current position on the XML buffer. */
char *_text; /** Buffer with the text being parsed */
+ char *_fileName;
ParserState _state; /** Internal state of the parser */
diff --git a/gui/InterfaceManager.cpp b/gui/InterfaceManager.cpp
index dc2250a2bd..5ee3a014ed 100644
--- a/gui/InterfaceManager.cpp
+++ b/gui/InterfaceManager.cpp
@@ -38,11 +38,44 @@ namespace GUI {
using namespace Graphics;
+const char *InterfaceManager::kDrawDataStrings[] = {
+ "mainmenu_bg",
+ "special_bg",
+ "plain_bg",
+ "default_bg",
+
+ "button_idle",
+ "button_hover",
+
+ "surface",
+
+ "slider_full",
+ "slider_empty",
+
+ "checkbox_enabled",
+ "checkbox_disabled",
+
+ "tab",
+
+ "scrollbar_base",
+ "scrollbar_top",
+ "scrollbar_bottom",
+ "scrollbar_handle",
+
+ "popup",
+ "caret",
+ "separator"
+};
+
InterfaceManager::InterfaceManager() :
_vectorRenderer(0), _system(0), _graphicsMode(kGfxDisabled),
_screen(0), _bytesPerPixel(0) {
_system = g_system;
+ for (int i = 0; i < kDrawDataMAX; ++i) {
+ _widgets[i] = 0;
+ }
+
setGraphicsMode(kGfxStandard16bit);
}
@@ -78,9 +111,25 @@ void InterfaceManager::setGraphicsMode(Graphics_Mode mode) {
}
void InterfaceManager::addDrawStep(Common::String &drawDataId, Graphics::DrawStep *step) {
- _widgets[getDrawDataId(drawDataId)]->_steps.push_back(step);
+ DrawData id = getDrawDataId(drawDataId);
+
+ assert(_widgets[id] != 0);
+ _widgets[id]->_steps.push_back(step);
}
+bool InterfaceManager::addDrawData(DrawData data_id, bool cached) {
+ assert(data_id >= 0 && data_id < kDrawDataMAX);
+
+ if (_widgets[data_id] != 0)
+ return false;
+
+ _widgets[data_id] = new WidgetDrawData;
+ _widgets[data_id]->_cached = cached;
+ _widgets[data_id]->_type = data_id;
+ _widgets[data_id]->_scaled = false;
+
+ return true;
+}
bool InterfaceManager::init() {
return false;
diff --git a/gui/InterfaceManager.h b/gui/InterfaceManager.h
index f5efb105ec..00441a9efc 100644
--- a/gui/InterfaceManager.h
+++ b/gui/InterfaceManager.h
@@ -47,6 +47,8 @@ class InterfaceManager : public Common::Singleton<InterfaceManager> {
friend class Common::Singleton<SingletonBaseType>;
typedef Common::String String;
+ static const char *kDrawDataStrings[];
+
public:
enum Graphics_Mode {
kGfxDisabled = 0,
@@ -168,10 +170,15 @@ public:
void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state = kStateEnabled);
DrawData getDrawDataId(Common::String &name) {
- return (DrawData)0;
+ for (int i = 0; i < kDrawDataMAX; ++i)
+ if (name.compareToIgnoreCase(kDrawDataStrings[i]) == 0)
+ return (DrawData)i;
+
+ return (DrawData)-1;
}
void addDrawStep(Common::String &drawDataId, Graphics::DrawStep *step);
+ bool addDrawData(DrawData data_id, bool cached);
protected:
template<typename PixelType> void screenInit();
diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp
index 9f029a874e..afc623c3d8 100644
--- a/gui/ThemeParser.cpp
+++ b/gui/ThemeParser.cpp
@@ -42,6 +42,15 @@ using namespace Common;
ThemeParser::ThemeParser() : XMLParser() {
_callbacks["drawstep"] = &ThemeParser::parserCallback_DRAWSTEP;
_callbacks["drawdata"] = &ThemeParser::parserCallback_DRAWDATA;
+
+ _drawFunctions["circle"] = &Graphics::VectorRenderer::drawCallback_CIRCLE;
+ _drawFunctions["square"] = &Graphics::VectorRenderer::drawCallback_SQUARE;
+ _drawFunctions["roundedsq"] = &Graphics::VectorRenderer::drawCallback_ROUNDSQ;
+ _drawFunctions["bevelsq"] = &Graphics::VectorRenderer::drawCallback_BEVELSQ;
+ _drawFunctions["line"] = &Graphics::VectorRenderer::drawCallback_LINE;
+ _drawFunctions["triangle"] = &Graphics::VectorRenderer::drawCallback_TRIANGLE;
+ _drawFunctions["fill"] = &Graphics::VectorRenderer::drawCallback_FILLSURFACE;
+ _drawFunctions["void"] = &Graphics::VectorRenderer::drawCallback_VOID;
}
bool ThemeParser::keyCallback(Common::String keyName) {
@@ -73,8 +82,12 @@ Graphics::DrawStep *ThemeParser::newDrawStep() {
}
bool ThemeParser::parserCallback_DRAWSTEP() {
- ParserNode *stepNode = _activeKey.pop();
- ParserNode *drawdataNode = _activeKey.pop();
+ ParserNode *stepNode = _activeKey.top();
+
+ // HACK: Any cleaner way to access the second item from
+ // the top without popping? Let's keep it this way and hope
+ // the internal representation doesn't change
+ ParserNode *drawdataNode = _activeKey[_activeKey.size() - 2];
assert(stepNode->name == "drawstep");
assert(drawdataNode->name == "drawdata");
@@ -85,32 +98,108 @@ bool ThemeParser::parserCallback_DRAWSTEP() {
Common::String functionName = stepNode->values["func"];
if (_drawFunctions.contains(functionName) == false) {
- parserError("Invalid drawing function in draw step.");
- _activeKey.push(drawdataNode);
- _activeKey.push(stepNode);
+ parserError("%s is not a valid drawing function name", functionName.c_str());
return false;
}
drawstep->drawingCall = _drawFunctions[functionName];
- if (stepNode->values.contains("stroke")) {
+ uint32 red, green, blue;
+/**
+ * Helper macro to sanitize and assign an integer value from a key
+ * to the draw step.
+ *
+ * @param struct_name Name of the field of a DrawStep struct that must be
+ * assigned.
+ * @param key_name Name as STRING of the key identifier as it appears in the
+ * theme description format.
+ */
+#define __PARSER_ASSIGN_INT(struct_name, key_name) \
+ if (stepNode->values.contains(key_name)) { \
+ if (!validateKeyInt(stepNode->values[key_name].c_str())) \
+ return false; \
+ \
+ drawstep->struct_name = atoi(stepNode->values[key_name].c_str()); \
+ }
+
+/**
+ * Helper macro to sanitize and assign a RGB value from a key to the draw
+ * step. RGB values have the following syntax: "R, G, B".
+ *
+ * TODO: Handle also specific name colors such as "red", "green", etc.
+ *
+ * @param struct_name Name of the field of a DrawStep struct that must be
+ * assigned.
+ * @param key_name Name as STRING of the key identifier as it appears in the
+ * theme description format.
+ */
+#define __PARSER_ASSIGN_RGB(struct_name, key_name) \
+ if (stepNode->values.contains(key_name)) { \
+ if (sscanf(stepNode->values[key_name].c_str(), "%d, %d, %d", &red, &green, &blue) != 3) \
+ return false; \
+ \
+ drawstep->struct_name.r = red; \
+ drawstep->struct_name.g = green; \
+ drawstep->struct_name.b = blue; \
}
- if (functionName == "roundedsq") {
+ __PARSER_ASSIGN_INT(stroke, "stroke");
+ __PARSER_ASSIGN_INT(shadow, "shadow");
+ __PARSER_ASSIGN_INT(factor, "gradient_factor");
+ __PARSER_ASSIGN_RGB(fgColor, "fg_color");
+ __PARSER_ASSIGN_RGB(bgColor, "bg_color");
+ __PARSER_ASSIGN_RGB(gradColor1, "gradient_start");
+ __PARSER_ASSIGN_RGB(gradColor2, "gradient_end");
+
+ if (functionName == "roundedsq" || functionName == "circle") {
+ __PARSER_ASSIGN_INT(radius, "radius");
}
- g_InterfaceManager.addDrawStep(drawdataNode->values["id"], drawstep);
+ if (functionName == "bevelsq") {
+ __PARSER_ASSIGN_INT(extraData, "bevel");
+ }
- _activeKey.push(drawdataNode);
- _activeKey.push(stepNode);
+#undef __PARSER_ASSIGN_INT
+#undef __PARSER_ASSIGN_RGB
+ g_InterfaceManager.addDrawStep(drawdataNode->values["id"], drawstep);
return true;
}
bool ThemeParser::parserCallback_DRAWDATA() {
- printf("Drawdata callback!\n");
+ ParserNode *drawdataNode = _activeKey.top();
+ bool cached = false;
+
+ if (drawdataNode->values.contains("id") == false) {
+ parserError("DrawData notes must contain an identifier.");
+ return false;
+ }
+
+ InterfaceManager::DrawData id = g_InterfaceManager.getDrawDataId(drawdataNode->values["id"]);
+
+ if (id == -1) {
+ parserError("%d is not a valid DrawData set identifier.", drawdataNode->values["id"].c_str());
+ return false;
+ }
+
+ if (drawdataNode->values.contains("cached") && drawdataNode->values["cached"] == "true") {
+ cached = true;
+ }
+
+ if (drawdataNode->values.contains("platform")) {
+ if (drawdataNode->values["platform"].compareToIgnoreCase(Common::getHostPlatformString()) != 0) {
+ drawdataNode->ignore = true;
+ return true;
+ }
+ }
+
+ if (g_InterfaceManager.addDrawData(id, cached) == false) {
+ parserError("Repeated DrawData: Only one set of Drawing Data for a widget may be specified on each platform.");
+ return false;
+ }
+
return true;
}
diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h
index 108a7263ba..4103098a63 100644
--- a/gui/ThemeParser.h
+++ b/gui/ThemeParser.h
@@ -321,6 +321,24 @@ protected:
bool parserCallback_DRAWSTEP();
bool parserCallback_DRAWDATA();
+ bool validateKeyIntSigned(const char *key) {
+ if (!isdigit(*key) && *key != '+' && *key != '-')
+ return false;
+
+ return validateKeyInt(key + 1);
+ }
+
+ bool validateKeyInt(const char *key) {
+ if (*key == 0)
+ return false;
+
+ while (*key)
+ if (!isdigit(*key++))
+ return false;
+
+ return true;
+ }
+
Graphics::DrawStep *newDrawStep();
Common::HashMap<Common::String, DrawingFunctionCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _drawFunctions;