diff options
Diffstat (limited to 'tools/localize/ValuesFile.cpp')
-rw-r--r-- | tools/localize/ValuesFile.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/tools/localize/ValuesFile.cpp b/tools/localize/ValuesFile.cpp new file mode 100644 index 000000000000..bd6f494d74e5 --- /dev/null +++ b/tools/localize/ValuesFile.cpp @@ -0,0 +1,266 @@ +#include "ValuesFile.h" + +#include "XMLHandler.h" + +#include <algorithm> +#include <fcntl.h> +#include <expat.h> +#include <unistd.h> +#include <errno.h> + +using namespace std; + +const char* const ANDROID_XMLNS = "http://schemas.android.com/apk/res/android"; +const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2"; + +const char *const NS_MAP[] = { + "android", ANDROID_XMLNS, + "xliff", XLIFF_XMLNS, + NULL, NULL +}; + +const XMLNamespaceMap ANDROID_NAMESPACES(NS_MAP); + + +// ===================================================================================== +class ArrayHandler : public XMLHandler +{ +public: + ArrayHandler(ValuesFile* vf, int version, const string& versionString, const string& id); + + virtual int OnStartElement(const SourcePos& pos, const string& ns, const string& name, + const vector<XMLAttribute>& attrs, XMLHandler** next); + virtual int OnText(const SourcePos& pos, const string& text); + virtual int OnComment(const SourcePos& pos, const string& text); + +private: + ValuesFile* m_vf; + int m_version; + int m_index; + string m_versionString; + string m_id; + string m_comment; +}; + +ArrayHandler::ArrayHandler(ValuesFile* vf, int version, const string& versionString, + const string& id) + :m_vf(vf), + m_version(version), + m_index(0), + m_versionString(versionString), + m_id(id) +{ +} + +int +ArrayHandler::OnStartElement(const SourcePos& pos, const string& ns, const string& name, + const vector<XMLAttribute>& attrs, XMLHandler** next) +{ + if (ns == "" && name == "item") { + XMLNode* node = XMLNode::NewElement(pos, ns, name, attrs, XMLNode::EXACT); + m_vf->AddString(StringResource(pos, pos.file, m_vf->GetConfiguration(), + m_id, m_index, node, m_version, m_versionString, + trim_string(m_comment))); + *next = new NodeHandler(node, XMLNode::EXACT); + m_index++; + m_comment = ""; + return 0; + } else { + pos.Error("invalid <%s> element inside <array>\n", name.c_str()); + return 1; + } +} + +int +ArrayHandler::OnText(const SourcePos& pos, const string& text) +{ + return 0; +} + +int +ArrayHandler::OnComment(const SourcePos& pos, const string& text) +{ + m_comment += text; + return 0; +} + +// ===================================================================================== +class ValuesHandler : public XMLHandler +{ +public: + ValuesHandler(ValuesFile* vf, int version, const string& versionString); + + virtual int OnStartElement(const SourcePos& pos, const string& ns, const string& name, + const vector<XMLAttribute>& attrs, XMLHandler** next); + virtual int OnText(const SourcePos& pos, const string& text); + virtual int OnComment(const SourcePos& pos, const string& text); + +private: + ValuesFile* m_vf; + int m_version; + string m_versionString; + string m_comment; +}; + +ValuesHandler::ValuesHandler(ValuesFile* vf, int version, const string& versionString) + :m_vf(vf), + m_version(version), + m_versionString(versionString) +{ +} + +int +ValuesHandler::OnStartElement(const SourcePos& pos, const string& ns, const string& name, + const vector<XMLAttribute>& attrs, XMLHandler** next) +{ + if (ns == "" && name == "string") { + string id = XMLAttribute::Find(attrs, "", "name", ""); + XMLNode* node = XMLNode::NewElement(pos, ns, name, attrs, XMLNode::EXACT); + m_vf->AddString(StringResource(pos, pos.file, m_vf->GetConfiguration(), + id, -1, node, m_version, m_versionString, + trim_string(m_comment))); + *next = new NodeHandler(node, XMLNode::EXACT); + } + else if (ns == "" && name == "array") { + string id = XMLAttribute::Find(attrs, "", "name", ""); + *next = new ArrayHandler(m_vf, m_version, m_versionString, id); + } + m_comment = ""; + return 0; +} + +int +ValuesHandler::OnText(const SourcePos& pos, const string& text) +{ + return 0; +} + +int +ValuesHandler::OnComment(const SourcePos& pos, const string& text) +{ + m_comment += text; + return 0; +} + +// ===================================================================================== +ValuesFile::ValuesFile(const Configuration& config) + :m_config(config), + m_strings(), + m_arrays() +{ +} + +ValuesFile::~ValuesFile() +{ +} + +ValuesFile* +ValuesFile::ParseFile(const string& filename, const Configuration& config, + int version, const string& versionString) +{ + ValuesFile* result = new ValuesFile(config); + + TopElementHandler top("", "resources", new ValuesHandler(result, version, versionString)); + XMLHandler::ParseFile(filename, &top); + + return result; +} + +ValuesFile* +ValuesFile::ParseString(const string& filename, const string& text, const Configuration& config, + int version, const string& versionString) +{ + ValuesFile* result = new ValuesFile(config); + + TopElementHandler top("", "resources", new ValuesHandler(result, version, versionString)); + XMLHandler::ParseString(filename, text, &top); + + return result; +} + +const Configuration& +ValuesFile::GetConfiguration() const +{ + return m_config; +} + +void +ValuesFile::AddString(const StringResource& str) +{ + if (str.index < 0) { + m_strings.insert(str); + } else { + m_arrays[str.id].insert(str); + } +} + +set<StringResource> +ValuesFile::GetStrings() const +{ + set<StringResource> result = m_strings; + + for (map<string,set<StringResource> >::const_iterator it = m_arrays.begin(); + it != m_arrays.end(); it++) { + result.insert(it->second.begin(), it->second.end()); + } + + return result; +} + +XMLNode* +ValuesFile::ToXMLNode() const +{ + XMLNode* root; + + // <resources> + { + vector<XMLAttribute> attrs; + ANDROID_NAMESPACES.AddToAttributes(&attrs); + root = XMLNode::NewElement(GENERATED_POS, "", "resources", attrs, XMLNode::PRETTY); + } + + // <array> + for (map<string,set<StringResource> >::const_iterator it = m_arrays.begin(); + it != m_arrays.end(); it++) { + vector<XMLAttribute> arrayAttrs; + arrayAttrs.push_back(XMLAttribute("", "name", it->first)); + const set<StringResource>& items = it->second; + XMLNode* arrayNode = XMLNode::NewElement(items.begin()->pos, "", "array", arrayAttrs, + XMLNode::PRETTY); + root->EditChildren().push_back(arrayNode); + + // <item> + for (set<StringResource>::const_iterator item = items.begin(); + item != items.end(); item++) { + XMLNode* itemNode = item->value->Clone(); + itemNode->SetName("", "item"); + itemNode->EditAttributes().clear(); + arrayNode->EditChildren().push_back(itemNode); + } + } + + // <string> + for (set<StringResource>::const_iterator it=m_strings.begin(); it!=m_strings.end(); it++) { + const StringResource& str = *it; + vector<XMLAttribute> attrs; + XMLNode* strNode = str.value->Clone(); + strNode->SetName("", "string"); + strNode->EditAttributes().clear(); + strNode->EditAttributes().push_back(XMLAttribute("", "name", str.id)); + root->EditChildren().push_back(strNode); + } + + return root; +} + +string +ValuesFile::ToString() const +{ + XMLNode* xml = ToXMLNode(); + string s = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; + s += xml->ToString(ANDROID_NAMESPACES); + delete xml; + s += '\n'; + return s; +} + |