#include "xmb.h"
#include "file_utils.h"
#include "localize.h"
#include "ValuesFile.h"
#include "XMLHandler.h"
#include "XLIFFFile.h"
#include <map>
#include <cstdio>
using namespace std;
const char *const NS_MAP[] = {
"xml", XMLNS_XMLNS,
NULL, NULL
};
set<string> g_tags;
static string
strip_newlines(const string& str)
{
string res;
const size_t N = str.length();
for (size_t i=0; i<N; i++) {
char c = str[i];
if (c != '\n' && c != '\r') {
res += c;
} else {
res += ' ';
}
}
return res;
}
static int
rename_id_attribute(XMLNode* node)
{
vector<XMLAttribute>& attrs = node->EditAttributes();
const size_t I = attrs.size();
for (size_t i=0; i<I; i++) {
XMLAttribute attr = attrs[i];
if (attr.name == "id") {
attr.name = "name";
attrs.erase(attrs.begin()+i);
attrs.push_back(attr);
return 0;
}
}
return 1;
}
static int
convert_xliff_to_ph(XMLNode* node, int* phID)
{
int err = 0;
if (node->Type() == XMLNode::ELEMENT) {
if (node->Namespace() == XLIFF_XMLNS) {
g_tags.insert(node->Name());
node->SetName("", "ph");
err = rename_id_attribute(node);
if (err != 0) {
char name[30];
(*phID)++;
sprintf(name, "id-%d", *phID);
node->EditAttributes().push_back(XMLAttribute("", "name", name));
err = 0;
}
}
vector<XMLNode*>& children = node->EditChildren();
const size_t I = children.size();
for (size_t i=0; i<I; i++) {
err |= convert_xliff_to_ph(children[i], phID);
}
}
return err;
}
XMLNode*
resource_to_xmb_msg(const StringResource& res)
{
// the msg element
vector<XMLAttribute> attrs;
string name = res.pos.file;
name += ":";
name += res.TypedID();
attrs.push_back(XMLAttribute("", "name", name));
attrs.push_back(XMLAttribute("", "desc", strip_newlines(res.comment)));
attrs.push_back(XMLAttribute(XMLNS_XMLNS, "space", "preserve"));
XMLNode* msg = XMLNode::NewElement(res.pos, "", "msg", attrs, XMLNode::EXACT);
// the contents are in xliff/html, convert it to xliff
int err = 0;
XMLNode* value = res.value;
string tag = value->Name();
int phID = 0;
for (vector<XMLNode*>::const_iterator it=value->Children().begin();
it!=value->Children().end(); it++) {
err |= convert_html_to_xliff(*it, tag, msg, &phID);
}
if (err != 0) {
return NULL;
}
// and then convert that to xmb
for (vector<XMLNode*>::iterator it=msg->EditChildren().begin();
it!=msg->EditChildren().end(); it++) {
err |= convert_xliff_to_ph(*it, &phID);
}
if (err == 0) {
return msg;
} else {
return NULL;
}
}
int
do_xlb_export(const string& outfile, const vector<string>& resFiles)
{
int err = 0;
size_t totalFileCount = resFiles.size();
Configuration english;
english.locale = "en_US";
set<StringResource> allResources;
const size_t J = resFiles.size();
for (size_t j=0; j<J; j++) {
string resFile = resFiles[j];
ValuesFile* valuesFile = get_local_values_file(resFile, english, CURRENT_VERSION, "", true);
if (valuesFile != NULL) {
set<StringResource> resources = valuesFile->GetStrings();
allResources.insert(resources.begin(), resources.end());
} else {
fprintf(stderr, "error reading file %s\n", resFile.c_str());
}
delete valuesFile;
}
// Construct the XLB xml
vector<XMLAttribute> attrs;
attrs.push_back(XMLAttribute("", "locale", "en"));
XMLNode* localizationbundle = XMLNode::NewElement(GENERATED_POS, "", "localizationbundle",
attrs, XMLNode::PRETTY);
for (set<StringResource>::iterator it=allResources.begin(); it!=allResources.end(); it++) {
XMLNode* msg = resource_to_xmb_msg(*it);
if (msg) {
localizationbundle->EditChildren().push_back(msg);
} else {
err = 1;
}
}
#if 0
for (set<string>::iterator it=g_tags.begin(); it!=g_tags.end(); it++) {
printf("tag: %s\n", it->c_str());
}
printf("err=%d\n", err);
#endif
if (err == 0) {
FILE* f = fopen(outfile.c_str(), "wb");
if (f == NULL) {
fprintf(stderr, "can't open outputfile: %s\n", outfile.c_str());
return 1;
}
fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
fprintf(f, "%s\n", localizationbundle->ToString(NS_MAP).c_str());
fclose(f);
}
return err;
}