1#include "xmb.h"
2
3#include "file_utils.h"
4#include "localize.h"
5#include "ValuesFile.h"
6#include "XMLHandler.h"
7#include "XLIFFFile.h"
8
9#include <map>
10#include <cstdio>
11
12using namespace std;
13
14const char *const NS_MAP[] = {
15    "xml", XMLNS_XMLNS,
16    NULL, NULL
17};
18
19set<string> g_tags;
20
21static string
22strip_newlines(const string& str)
23{
24    string res;
25    const size_t N = str.length();
26    for (size_t i=0; i<N; i++) {
27        char c = str[i];
28        if (c != '\n' && c != '\r') {
29            res += c;
30        } else {
31            res += ' ';
32        }
33    }
34    return res;
35}
36
37static int
38rename_id_attribute(XMLNode* node)
39{
40    vector<XMLAttribute>& attrs = node->EditAttributes();
41    const size_t I = attrs.size();
42    for (size_t i=0; i<I; i++) {
43        XMLAttribute attr = attrs[i];
44        if (attr.name == "id") {
45            attr.name = "name";
46            attrs.erase(attrs.begin()+i);
47            attrs.push_back(attr);
48            return 0;
49        }
50    }
51    return 1;
52}
53
54static int
55convert_xliff_to_ph(XMLNode* node, int* phID)
56{
57    int err = 0;
58    if (node->Type() == XMLNode::ELEMENT) {
59        if (node->Namespace() == XLIFF_XMLNS) {
60            g_tags.insert(node->Name());
61            node->SetName("", "ph");
62
63            err = rename_id_attribute(node);
64            if (err != 0) {
65                char name[30];
66                (*phID)++;
67                sprintf(name, "id-%d", *phID);
68                node->EditAttributes().push_back(XMLAttribute("", "name", name));
69                err = 0;
70            }
71        }
72        vector<XMLNode*>& children = node->EditChildren();
73        const size_t I = children.size();
74        for (size_t i=0; i<I; i++) {
75            err |= convert_xliff_to_ph(children[i], phID);
76        }
77    }
78    return err;
79}
80
81XMLNode*
82resource_to_xmb_msg(const StringResource& res)
83{
84    // the msg element
85    vector<XMLAttribute> attrs;
86    string name = res.pos.file;
87    name += ":";
88    name += res.TypedID();
89    attrs.push_back(XMLAttribute("", "name", name));
90    attrs.push_back(XMLAttribute("", "desc", strip_newlines(res.comment)));
91    attrs.push_back(XMLAttribute(XMLNS_XMLNS, "space", "preserve"));
92    XMLNode* msg = XMLNode::NewElement(res.pos, "", "msg", attrs, XMLNode::EXACT);
93
94    // the contents are in xliff/html, convert it to xliff
95    int err = 0;
96    XMLNode* value = res.value;
97    string tag = value->Name();
98    int phID = 0;
99    for (vector<XMLNode*>::const_iterator it=value->Children().begin();
100            it!=value->Children().end(); it++) {
101        err |= convert_html_to_xliff(*it, tag, msg, &phID);
102    }
103
104    if (err != 0) {
105        return NULL;
106    }
107
108    // and then convert that to xmb
109    for (vector<XMLNode*>::iterator it=msg->EditChildren().begin();
110            it!=msg->EditChildren().end(); it++) {
111        err |= convert_xliff_to_ph(*it, &phID);
112    }
113
114    if (err == 0) {
115        return msg;
116    } else {
117        return NULL;
118    }
119}
120
121int
122do_xlb_export(const string& outfile, const vector<string>& resFiles)
123{
124    int err = 0;
125
126    size_t totalFileCount = resFiles.size();
127
128    Configuration english;
129        english.locale = "en_US";
130
131    set<StringResource> allResources;
132
133    const size_t J = resFiles.size();
134    for (size_t j=0; j<J; j++) {
135        string resFile = resFiles[j];
136
137        ValuesFile* valuesFile = get_local_values_file(resFile, english, CURRENT_VERSION, "", true);
138        if (valuesFile != NULL) {
139            set<StringResource> resources = valuesFile->GetStrings();
140            allResources.insert(resources.begin(), resources.end());
141        } else {
142            fprintf(stderr, "error reading file %s\n", resFile.c_str());
143        }
144
145        delete valuesFile;
146    }
147
148    // Construct the XLB xml
149    vector<XMLAttribute> attrs;
150    attrs.push_back(XMLAttribute("", "locale", "en"));
151    XMLNode* localizationbundle = XMLNode::NewElement(GENERATED_POS, "", "localizationbundle",
152            attrs, XMLNode::PRETTY);
153
154    for (set<StringResource>::iterator it=allResources.begin(); it!=allResources.end(); it++) {
155        XMLNode* msg = resource_to_xmb_msg(*it);
156        if (msg) {
157            localizationbundle->EditChildren().push_back(msg);
158        } else {
159            err = 1;
160        }
161    }
162
163#if 0
164    for (set<string>::iterator it=g_tags.begin(); it!=g_tags.end(); it++) {
165        printf("tag: %s\n", it->c_str());
166    }
167    printf("err=%d\n", err);
168#endif
169    if (err == 0) {
170        FILE* f = fopen(outfile.c_str(), "wb");
171        if (f == NULL) {
172            fprintf(stderr, "can't open outputfile: %s\n", outfile.c_str());
173            return 1;
174        }
175        fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
176        fprintf(f, "%s\n", localizationbundle->ToString(NS_MAP).c_str());
177        fclose(f);
178    }
179
180    return err;
181}
182
183