134{
135 std::string filename, contents;
136 const unsigned char *data;
137 size_t datalen;
138 size_t idx;
139 unsigned char chunk_type;
145
146 i18n_log(
"i18n_set_language(" << directory <<
"," << base <<
")");
147 if (!directory || !base)
148 return -1;
149
150 if (language.empty())
152 filename = std::string(directory) + "/" + base + "_" + language + ".qm";
153 i18n_log(
"Loading translations for language " << language);
154
155 boost::system::error_code ignored_ec;
156 if (boost::filesystem::exists(filename, ignored_ec)) {
158 i18n_log(
"Failed to load translations file: " << filename);
159 return -1;
160 }
161 } else {
162 i18n_log(
"Translations file not found: " << filename);
163 filename = std::string(base) + "_" + language + ".qm";
164 if (!find_embedded_file(filename, contents)) {
165 i18n_log(
"Embedded translations file not found: " << filename);
166 const char *underscore = strchr(language.c_str(), '_');
167 if (underscore) {
168 std::string fallback_language = std::string(language, 0, underscore - language.c_str());
169 filename = std::string(directory) + "/" + base + "_" + fallback_language + ".qm";
170 i18n_log(
"Loading translations for language " << fallback_language);
171 if (boost::filesystem::exists(filename, ignored_ec)) {
173 i18n_log(
"Failed to load translations file: " << filename);
174 return -1;
175 }
176 } else {
177 i18n_log(
"Translations file not found: " << filename);
178 filename = std::string(base) + "_" + fallback_language + ".qm";
179 if (!find_embedded_file(filename, contents)) {
180 i18n_log(
"Embedded translations file not found: " << filename);
181 return -1;
182 }
183 }
184 } else {
185 return -1;
186 }
187 }
188 }
189
190 data = (const unsigned char*)contents.c_str();
191 datalen = contents.size();
192 idx = 0;
193 i18n_log(
"Translations file size: " << datalen);
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 if (datalen < sizeof(qm_magic) || memcmp(data, qm_magic, sizeof(qm_magic))) {
221 i18n_log(
"Bad translations file format: " << filename);
222 return -1;
223 }
224 idx += sizeof(qm_magic);
225
226 while (idx < datalen) {
227 if (idx + 5 > datalen) {
228 i18n_log(
"Bad translations file format: " << filename);
229 return -1;
230 }
231 chunk_type = data[idx++];
232 chunk_size = be32(data+idx);
233 idx += 4;
234
235 i18n_log(
"Found " << chunk_type <<
" of " << chunk_size <<
" bytes");
236 if (chunk_size >= datalen || idx > datalen - chunk_size) {
237 i18n_log(
"Bad translations file format: " << filename);
238 return -1;
239 }
240
241 switch (chunk_type) {
242 case 0x42:
243 i18n_log(
"Found offsets at " << idx);
244
245 offsets_idx = idx;
246 num_messages = chunk_size / 8;
247 break;
248 case 0x69:
249 i18n_log(
"Found messages at " << idx);
250 messages_idx = idx;
251 break;
252 default:
253 i18n_log(
"Found unsupported chunk type: " << chunk_type);
254 break;
255 }
256
257 idx += chunk_size;
258 }
259
262 return -1;
263 }
265 i18n_log(
"No messages chunk found");
266 return -1;
267 }
268
269 for (
uint32_t m = 0; m < num_messages; ++m) {
270 be32(data+offsets_idx+m*8);
271 idx = be32(data+offsets_idx+m*8+4);
272 idx += messages_idx;
273
274 if (idx > datalen || idx + 1 > datalen) {
275 i18n_log(
"Bad translations file format: " << filename);
276 return -1;
277 }
278
279 while (1) {
280 if (idx + 5 > datalen) {
281 i18n_log(
"Bad translations file format: " << filename);
282 return -1;
283 }
284 chunk_type = data[idx++];
285 chunk_size = 0;
286 if (chunk_type == 0x01) {
287 i18n_entries[
context + std::string(
"",1) +
source] = translation;
290 translation = std::string();
291 break;
292 }
293
294 chunk_size = be32(data+idx);
295 idx += 4;
296 i18n_log(
"Found " << chunk_type <<
" of " << chunk_size <<
" bytes");
297 if (chunk_size >= datalen || idx > datalen - chunk_size) {
298 i18n_log(
"Bad translations file format: " << filename);
299 return -1;
300 }
301 switch (chunk_type) {
302 case 0x03:
303 translation = utf16(data+idx, chunk_size);
304 i18n_log(
"Found translation: " << translation);
305 break;
306 case 0x06:
307 source = utf8(data+idx, chunk_size);
309 break;
310 case 0x07:
311 context = utf8(data+idx, chunk_size);
312 i18n_log(
"Found context: " << context);
313 break;
314 }
315 idx += chunk_size;
316 }
317 }
318
319 return 0;
320}
std::string i18n_get_language()
bool load_file_to_string(const std::string &path_to_file, std::string &target_str, size_t max_size=1000000000)
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
const CharType(& source)[N]