gui: support string resources

storing strings in a map (for fast lookup) in resource manager

To define a string resource in <resources>:
<string name="foo">Hello</string>

To use a string, e.g.:
<text>%@foo%</text>

Not yet done: language-specific resources (should be solved not only for
strings, but for all kinds of resources - e.g. for localized images)

Change-Id: I3ba5cf5298c09e0d28a83973e9662f179271b33f
diff --git a/gui/gui.cpp b/gui/gui.cpp
index f3d31d7..cd6f45d 100644
--- a/gui/gui.cpp
+++ b/gui/gui.cpp
@@ -729,35 +729,37 @@
 	return 0;
 }
 
-std::string gui_parse_text(string inText)
+std::string gui_parse_text(std::string str)
 {
-	// Copied from std::string GUIText::parseText(void)
 	// This function parses text for DataManager values encompassed by %value% in the XML
-	static int counter = 0;
-	std::string str = inText;
+	// and string resources (%@resource_name%)
 	size_t pos = 0;
-	size_t next = 0, end = 0;
 
 	while (1)
 	{
-		next = str.find('%', pos);
+		size_t next = str.find('%', pos);
 		if (next == std::string::npos)
 			return str;
 
-		end = str.find('%', next + 1);
+		size_t end = str.find('%', next + 1);
 		if (end == std::string::npos)
 			return str;
 
 		// We have a block of data
-		std::string var = str.substr(next + 1,(end - next) - 1);
-		str.erase(next,(end - next) + 1);
+		std::string var = str.substr(next + 1, (end - next) - 1);
+		str.erase(next, (end - next) + 1);
 
 		if (next + 1 == end)
 			str.insert(next, 1, '%');
 		else
 		{
 			std::string value;
-			if (DataManager::GetValue(var, value) == 0)
+			if (var.size() > 0 && var[0] == '@') {
+				// this is a string resource ("%@string_name%")
+				value = PageManager::GetResources()->FindString(var.substr(1));
+				str.insert(next, value);
+			}
+			else if (DataManager::GetValue(var, value) == 0)
 				str.insert(next, value);
 		}
 
diff --git a/gui/objects.hpp b/gui/objects.hpp
index a86747a..2611411 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -217,9 +217,6 @@
 	int mFontHeight;
 	unsigned maxWidth;
 	unsigned charSkip;
-
-protected:
-	std::string parseText(void);
 };
 
 // GUIImage - Used for static image
diff --git a/gui/resources.cpp b/gui/resources.cpp
index 563dcc4..dcd4ca8 100644
--- a/gui/resources.cpp
+++ b/gui/resources.cpp
@@ -4,22 +4,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <fcntl.h>
-#include <sys/reboot.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <time.h>
 #include <unistd.h>
-#include <stdlib.h>
 
 #include <string>
 #include <sstream>
 #include <iostream>
 #include <iomanip>
 
+#include "../minzip/Zip.h"
 extern "C" {
 #include "../twcommon.h"
 #include "../minuitwrp/minui.h"
@@ -282,6 +274,14 @@
 	return NULL;
 }
 
+std::string ResourceManager::FindString(const std::string& name) const
+{
+	std::map<std::string, std::string>::const_iterator it = mStrings.find(name);
+	if (it != mStrings.end())
+		return it->second;
+	return "[" + name + ("]");
+}
+
 ResourceManager::ResourceManager()
 {
 }
@@ -339,6 +339,13 @@
 				delete res;
 			}
 		}
+		else if (type == "string")
+		{
+			if (xml_attribute<>* attr = child->first_attribute("name"))
+				mStrings[attr->value()] = child->value();
+			else
+				error = true;
+		}
 		else
 		{
 			LOGERR("Resource type (%s) not supported.\n", type.c_str());
diff --git a/gui/resources.hpp b/gui/resources.hpp
index 83fc7a5..0ce9684 100644
--- a/gui/resources.hpp
+++ b/gui/resources.hpp
@@ -3,7 +3,11 @@
 #ifndef _RESOURCE_HEADER
 #define _RESOURCE_HEADER
 
-#include "../minzip/Zip.h"
+#include <string>
+#include <vector>
+#include <map>
+
+struct ZipArchive;
 
 extern "C" {
 #include "../minuitwrp/minui.h"
@@ -94,11 +98,13 @@
 	FontResource* FindFont(const std::string& name) const;
 	ImageResource* FindImage(const std::string& name) const;
 	AnimationResource* FindAnimation(const std::string& name) const;
+	std::string FindString(const std::string& name) const;
 
 private:
 	std::vector<FontResource*> mFonts;
 	std::vector<ImageResource*> mImages;
 	std::vector<AnimationResource*> mAnimations;
+	std::map<std::string, std::string> mStrings;
 };
 
 #endif  // _RESOURCE_HEADER
diff --git a/gui/text.cpp b/gui/text.cpp
index 3487f7a..effb935 100644
--- a/gui/text.cpp
+++ b/gui/text.cpp
@@ -55,7 +55,7 @@
 	if (child)  mText = child->value();
 
 	// Simple way to check for static state
-	mLastValue = parseText();
+	mLastValue = gui_parse_text(mText);
 	if (mLastValue != mText)   mIsStatic = 0;
 
 	mFontHeight = mFont->GetHeight();
@@ -70,7 +70,7 @@
 	if (mFont)
 		fontResource = mFont->GetResource();
 
-	mLastValue = parseText();
+	mLastValue = gui_parse_text(mText);
 	string displayValue = mLastValue;
 
 	if (charSkip)
@@ -126,7 +126,7 @@
 	if (mIsStatic || !mVarChanged)
 		return 0;
 
-	std::string newValue = parseText();
+	std::string newValue = gui_parse_text(mText);
 	if (mLastValue == newValue)
 		return 0;
 	else
@@ -142,44 +142,11 @@
 		fontResource = mFont->GetResource();
 
 	h = mFontHeight;
-	mLastValue = parseText();
+	mLastValue = gui_parse_text(mText);
 	w = gr_measureEx(mLastValue.c_str(), fontResource);
 	return 0;
 }
 
-std::string GUIText::parseText(void)
-{
-	static int counter = 0;
-	std::string str = mText;
-	size_t pos = 0;
-	size_t next = 0, end = 0;
-
-	while (1)
-	{
-		next = str.find('%', pos);
-		if (next == std::string::npos) return str;
-		end = str.find('%', next + 1);
-		if (end == std::string::npos) return str;
-
-		// We have a block of data
-		std::string var = str.substr(next + 1, (end - next) - 1);
-		str.erase(next, (end - next) + 1);
-
-		if (next + 1 == end)
-		{
-			str.insert(next, 1, '%');
-		}
-		else
-		{
-			std::string value;
-			if (DataManager::GetValue(var, value) == 0)
-				str.insert(next, value);
-		}
-
-		pos = next + 1;
-	}
-}
-
 int GUIText::NotifyVarChange(const std::string& varName, const std::string& value)
 {
 	GUIObject::NotifyVarChange(varName, value);