Delete all Trailing spaces in code.
[reactos.git] / rosapps / smartpdf / src / translations.cpp
1 #include "base_util.h"
2 #include "translations.h"
3 #include "translations_txt.h"
4 #include "str_util.h"
5
6 /*
7 This code relies on the following variables that must be defined in a
8 separate file (translations_txt.h and translations_txt.c).
9 The idea is that those files are automatically generated
10 by a script from translations file.
11
12 // number of languages we support
13 int g_transLangsCount;
14
15 // array of language names so that g_transLangs[i] is a name of
16 // language. i is 0..g_transLangsCount-1
17 const char **g_transLangs;
18
19 // total number of translated strings
20 int g_transTranslationsCount;
21
22 // array of translated strings.
23 // it has g_transLangsCount * g_translationsCount elements
24 // (for simplicity). Translation i for language n is at position
25 // (n * g_transTranslationsCount) + i
26 const char **g_transTranslations;
27 */
28
29 // numeric index of the current language. 0 ... g_transLangsCount-1
30 static int currLangIdx = 0;
31
32 /* 'data'/'data_len' is a text describing all texts we translate.
33 It builds data structures need for quick lookup of translations
34 as well as a list of available languages.
35 It returns a list of available languages.
36 The list is not valid after a call to Translations_FreeData.
37 The function must be called before any other function in this module.
38 It can be called multiple times. This is to make debugging of translations
39 easier by allowing re-loading translation file at runtime.
40 */
41 bool Translations_FromData(const char* langs, const char* data, size_t data_len)
42 {
43 assert(0); // TODO: implement me
44 return false;
45 }
46
47 bool Translations_SetCurrentLanguage(const char* lang)
48 {
49 for (int i=0; i < g_transLangsCount; i++) {
50 if (str_eq(lang, g_transLangs[i])) {
51 currLangIdx = i;
52 return true;
53 }
54 }
55 return false;
56 }
57
58 const char* Translatations_GetTranslation(const char* txt)
59 {
60 // perf shortcut: don't bother translating if we use default lanuage
61 if (0 == currLangIdx)
62 return txt;
63 for (int i=0; i < g_transTranslationsCount; i++) {
64 // TODO: translations are sorted so can use binary search
65 const char *tmp = g_transTranslations[i];
66 int cmp_res = strcmp(txt, tmp);
67 if (0 == cmp_res) {
68 tmp = g_transTranslations[(currLangIdx * g_transTranslationsCount) + i];
69 if (NULL == tmp)
70 return txt;
71 return tmp;
72 } else if (cmp_res < 0) {
73 assert(0); // bad - didn't find a translation
74 return txt;
75 }
76 }
77 assert(0); // bad - didn't find a translation
78 return txt;
79 }
80
81 static WCHAR* lastTxtCached = NULL;
82
83 #define UTF8_END -1
84 #define UTF8_ERROR -2
85
86 typedef struct json_utf8_decode
87 {
88 int the_index;
89 const char *the_input;
90 int the_length;
91 int the_char;
92 int the_byte;
93 } json_utf8_decode;
94
95
96 void
97 utf8_decode_init(json_utf8_decode *utf8, const char *p, int length)
98 {
99 utf8->the_index = 0;
100 utf8->the_input = p;
101 utf8->the_length = length;
102 utf8->the_char = 0;
103 utf8->the_byte = 0;
104 }
105
106 static int
107 get(json_utf8_decode *utf8)
108 {
109 int c;
110 if (utf8->the_index >= utf8->the_length) {
111 return UTF8_END;
112 }
113 c = utf8->the_input[utf8->the_index] & 0xFF;
114 utf8->the_index += 1;
115 return c;
116 }
117
118 static int
119 cont(json_utf8_decode *utf8)
120 {
121 int c = get(utf8);
122 return ((c & 0xC0) == 0x80) ? (c & 0x3F) : UTF8_ERROR;
123 }
124
125 int
126 utf8_decode_next(json_utf8_decode *utf8)
127 {
128 int c; /* the first byte of the character */
129 int r; /* the result */
130
131 if (utf8->the_index >= utf8->the_length) {
132 return utf8->the_index == utf8->the_length ? UTF8_END : UTF8_ERROR;
133 }
134 utf8->the_byte = utf8->the_index;
135 utf8->the_char += 1;
136 c = get(utf8);
137 /*
138 Zero continuation (0 to 127)
139 */
140 if ((c & 0x80) == 0) {
141 return c;
142 }
143 /*
144 One contination (128 to 2047)
145 */
146 if ((c & 0xE0) == 0xC0) {
147 int c1 = cont(utf8);
148 if (c1 < 0) {
149 return UTF8_ERROR;
150 }
151 r = ((c & 0x1F) << 6) | c1;
152 return r >= 128 ? r : UTF8_ERROR;
153 }
154 /*
155 Two continuation (2048 to 55295 and 57344 to 65535)
156 */
157 if ((c & 0xF0) == 0xE0) {
158 int c1 = cont(utf8);
159 int c2 = cont(utf8);
160 if (c1 < 0 || c2 < 0) {
161 return UTF8_ERROR;
162 }
163 r = ((c & 0x0F) << 12) | (c1 << 6) | c2;
164 return r >= 2048 && (r < 55296 || r > 57343) ? r : UTF8_ERROR;
165 }
166 /*
167 Three continuation (65536 to 1114111)
168 */
169 if ((c & 0xF1) == 0xF0) {
170 int c1 = cont(utf8);
171 int c2 = cont(utf8);
172 int c3 = cont(utf8);
173 if (c1 < 0 || c2 < 0 || c3 < 0) {
174 return UTF8_ERROR;
175 }
176 r = ((c & 0x0F) << 18) | (c1 << 12) | (c2 << 6) | c3;
177 return r >= 65536 && r <= 1114111 ? r : UTF8_ERROR;
178 }
179 return UTF8_ERROR;
180 }
181
182 static int json_utf8_to_utf16(unsigned short *w, const char *p, int length)
183 {
184 int c;
185 int the_index = 0;
186 json_utf8_decode utf8;
187
188 utf8_decode_init(&utf8, p, length);
189 for (;;) {
190 c = utf8_decode_next(&utf8);
191 if (c < 0) {
192 return UTF8_END ? the_index : UTF8_ERROR;
193 }
194 if (c < 0x10000) {
195 w[the_index] = (unsigned short)c;
196 the_index += 1;
197 } else {
198 c &= 0xFFFF;
199 w[the_index] = (unsigned short)(0xD800 | (c >> 10));
200 the_index += 1;
201 w[the_index] = (unsigned short)(0xDC00 | (c & 0x3FF));
202 the_index += 1;
203 }
204 }
205 }
206
207 WCHAR* utf8_to_utf16(const char *txt)
208 {
209 // TODO: this is not correct, need real conversion
210 size_t len = strlen(txt);
211 WCHAR* wstr = (WCHAR*)zmalloc((len+1) * sizeof(WCHAR));
212 if (!wstr) return NULL;
213 int res = json_utf8_to_utf16((unsigned short*)wstr, txt, len);
214 assert(UTF8_ERROR != res);
215 return wstr;
216 }
217
218 // TODO: this is not thread-safe. lastTxtCached should be per-thread
219 const WCHAR* Translatations_GetTranslationW(const char* txt)
220 {
221 txt = Translatations_GetTranslation(txt);
222 if (!txt) return NULL;
223 if (lastTxtCached)
224 free(lastTxtCached);
225 lastTxtCached = utf8_to_utf16(txt);
226 return (const WCHAR*)lastTxtCached;
227 }
228
229 void Translations_FreeData()
230 {
231 // TODO: will be more when we implement Translations_FromData
232 free(lastTxtCached);
233 lastTxtCached = NULL;
234 }
235