5#include "qplatformdefs.h"
9#ifndef QT_NO_TRANSLATION
28#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
30# include "private/qcore_unix_p.h"
43#include <QtCore/qmutex.h>
55
56
57
58
63 0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95,
64 0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd
69static bool match(
const uchar *found, uint foundLen,
const char *target, uint targetLen)
73 if (foundLen > 0 && found[foundLen-1] ==
'\0')
75 return ((targetLen == foundLen) && memcmp(found, target, foundLen) == 0);
83 k = (
const uchar *) name;
86 if ((g = (h & 0xf0000000)) != 0)
107
108
109
110
111
122 uchar opcode = rules[offset];
123 uchar op = opcode & Q_OP_MASK;
128 if (++offset == rulesSize)
142 if (offset != rulesSize) {
154 if (offset == rulesSize)
157 }
while (((rules[offset] == Q_AND)
158 || (rules[offset] == Q_OR)
159 || (rules[offset] == Q_NEWRULE))
160 && ++offset != rulesSize);
167
168
169
170
171
172
173
174
175
176
177
178
179
189 bool orExprTruthValue =
false;
192 bool andExprTruthValue =
true;
195 bool truthValue =
true;
196 int opcode = rules[i++];
199 if (opcode & Q_MOD_10) {
201 }
else if (opcode & Q_MOD_100) {
203 }
else if (opcode & Q_LEAD_1000) {
204 while (leftOperand >= 1000)
208 int op = opcode & Q_OP_MASK;
209 int rightOperand = rules[i++];
213 truthValue = (leftOperand == rightOperand);
216 truthValue = (leftOperand < rightOperand);
219 truthValue = (leftOperand <= rightOperand);
222 int bottom = rightOperand;
223 int top = rules[i++];
224 truthValue = (leftOperand >= bottom && leftOperand <= top);
228 truthValue = !truthValue;
230 andExprTruthValue = andExprTruthValue && truthValue;
232 if (i == rulesSize || rules[i] != Q_AND)
237 orExprTruthValue = orExprTruthValue || andExprTruthValue;
239 if (i == rulesSize || rules[i] != Q_OR)
244 if (orExprTruthValue)
261 Q_DECLARE_PUBLIC(QTranslator)
268#if defined(QT_USE_MMAP)
275#if defined(QT_USE_MMAP)
301 bool load_translation(
const QStringList &languages,
const QString &filename,
const QString &prefix,
302 const QString &directory,
const QString &suffix);
303 bool do_load(
const QString &filename,
const QString &directory);
304 bool do_load(
const uchar *data, qsizetype len,
const QString &directory);
305 QString
do_translate(
const char *context,
const char *sourceText,
const char *comment,
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
400
401
402
404QTranslator::QTranslator(QObject * parent)
405 : QObject(*
new QTranslatorPrivate, parent)
410
411
413QTranslator::~QTranslator()
415 if (QCoreApplication::instanceExists())
416 QCoreApplication::removeTranslator(
this);
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
466bool QTranslator::load(
const QString & filename,
const QString & directory,
467 const QString & search_delimiters,
468 const QString & suffix)
471 QMutexLocker locker(&d->lock);
475 if (QFileInfo(filename).isRelative()) {
477 if (prefix.size() && !prefix.endsWith(u'/'))
481 const QString suffixOrDotQM = suffix.isNull() ? dotQmLiteral() : suffix;
482 QStringView fname(filename);
484 const QString delims = search_delimiters.isNull() ?
QStringLiteral(
"_.") : search_delimiters;
489 realname = prefix + fname + suffixOrDotQM;
490 fi.setFile(realname);
491 if (fi.isReadable() && fi.isFile())
494 realname = prefix + fname;
495 fi.setFile(realname);
496 if (fi.isReadable() && fi.isFile())
499 qsizetype rightmost = 0;
500 for (
auto ch : delims)
501 rightmost = std::max(rightmost, fname.lastIndexOf(ch));
507 fname.truncate(rightmost);
511 return d->do_load(realname, directory);
519 if (realname.startsWith(u':')) {
522 Q_ASSERT(!d->resource);
524 if (resource->isValid() && resource->compressionAlgorithm() == QResource::NoCompression
525 && resource->size() >= MagicLength
526 && !memcmp(resource->data(), magic, MagicLength)) {
527 d->unmapLength = resource->size();
528 d->unmapPointer =
reinterpret_cast<
char *>(
const_cast<uchar *>(resource->data()));
529#if defined(QT_USE_MMAP)
530 d->used_mmap =
false;
539 QFile file(realname);
540 if (!file.open(QIODevice::ReadOnly | QIODevice::Unbuffered))
543 qint64 fileSize = file.size();
544 if (fileSize < MagicLength || fileSize > std::numeric_limits<qsizetype>::max())
549 if (MagicLength != file.read(magicBuffer, MagicLength)
550 || memcmp(magicBuffer, magic, MagicLength))
554 d->unmapLength = qsizetype(fileSize);
562#define MAP_FAILED reinterpret_cast<void *>(-1
)
565 int fd = file.handle();
567 int protection = PROT_READ;
568 int flags = MAP_FILE | MAP_PRIVATE;
569 void *ptr = QT_MMAP(
nullptr, d->unmapLength,
572 if (ptr != MAP_FAILED) {
575 d->unmapPointer =
static_cast<
char *>(ptr);
585 qint64 readResult = file.read(d->unmapPointer, d->unmapLength);
586 if (readResult == qint64(unmapLength))
593 const QString base_dir =
594 !directory.isEmpty() ? directory : QFileInfo(realname).absolutePath();
597 d->filePath = realname;
602#if defined(QT_USE_MMAP)
605 munmap(unmapPointer, unmapLength);
611 d->resource =
nullptr;
619 const QString &filename,
620 const QString &prefix,
621 const QString &directory,
622 const QString &suffix)
624 qCDebug(lcTranslator).noquote().nospace() <<
"Searching translation for "
625 << filename << prefix << languages << suffix
626 <<
" in " << directory;
630 if (!path.isEmpty() && !path.endsWith(u'/'))
633 const QString suffixOrDotQM = suffix.isNull() ? dotQmLiteral() : suffix;
636 realname += path + filename + prefix;
637 const qsizetype realNameBaseSize = realname.size();
648 auto loadFile = [
this, &realname, &directory] {
return do_load(realname, directory); };
650 for (
const QString &localeName : languages) {
651 QString loc = localeName;
655 realname += loc + suffixOrDotQM;
660 realname.truncate(realNameBaseSize + loc.size());
664 realname.truncate(realNameBaseSize);
667 if (loc != localeName)
669 loc = std::move(loc).toLower();
670 if (loc == localeName)
675 const qsizetype realNameBaseSizeFallbacks = path.size() + filename.size();
678 if (!suffix.isNull()) {
679 realname.replace(realNameBaseSizeFallbacks, prefix.size(), suffix);
683 realname.replace(realNameBaseSizeFallbacks, suffix.size(), prefix);
690 realname.truncate(realNameBaseSizeFallbacks);
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738bool QTranslator::load(
const QLocale & locale,
739 const QString & filename,
740 const QString & prefix,
741 const QString & directory,
742 const QString & suffix)
745 const QStringList languages = locale.uiLanguages(QLocale::TagSeparator::Underscore);
746 qCDebug(lcTranslator) <<
"Requested UI languages" << languages;
747 QMutexLocker locker(&d->lock);
749 return d->load_translation(languages, filename, prefix, directory, suffix);
753
754
755
756
757
758
759
760
761
762
763
764bool QTranslator::load(
const uchar *data,
int len,
const QString &directory)
767 QMutexLocker locker(&d->lock);
770 if (!data || len < MagicLength || memcmp(data, magic, MagicLength))
773 return d->do_load(data, len, directory);
778 return qFromBigEndian<quint8>(data);
783 return qFromBigEndian<quint16>(data);
788 return qFromBigEndian<quint32>(data);
794 const uchar *end = data + len;
798 QStringList dependencies;
799 while (data < end - 5) {
800 quint8 tag = read8(data++);
801 quint32 blockLen = read32(data);
803 if (!tag || !blockLen)
805 if (quint32(end - data) < blockLen) {
810 if (tag == QTranslatorPrivate::Language) {
811 language = QString::fromUtf8((
const char *)data, blockLen);
812 }
else if (tag == QTranslatorPrivate::Contexts) {
815 }
else if (tag == QTranslatorPrivate::Hashes) {
818 }
else if (tag == QTranslatorPrivate::Messages) {
821 }
else if (tag == QTranslatorPrivate::NumerusRules) {
822 numerusRulesArray = data;
824 }
else if (tag == QTranslatorPrivate::Dependencies) {
825 QDataStream stream(QByteArray::fromRawData((
const char*)data, blockLen));
827 while (!stream.atEnd()) {
829 dependencies.append(dep);
836 if (ok && !isValidNumerusRules(numerusRulesArray, numerusRulesLength))
839 subTranslators.reserve(std::size_t(dependencies.size()));
840 for (
const QString &dependency : std::as_const(dependencies)) {
841 auto translator = std::make_unique<QTranslator>();
842 ok = translator->load(dependency, directory);
845 subTranslators.push_back(std::move(translator));
850 subTranslators.clear();
854 messageArray =
nullptr;
855 contextArray =
nullptr;
856 offsetArray =
nullptr;
857 numerusRulesArray =
nullptr;
867static QString
getMessage(
const uchar *m,
const uchar *end,
const char *context,
868 const char *sourceText,
const char *comment, uint numerus)
870 const uchar *tn =
nullptr;
872 const uint sourceTextLen = uint(strlen(sourceText));
873 const uint contextLen = uint(strlen(context));
874 const uint commentLen = uint(strlen(comment));
899 quint32 len = read32(m);
901 if (!match(m, len, sourceText, sourceTextLen))
907 quint32 len = read32(m);
909 if (!match(m, len, context, contextLen))
915 quint32 len = read32(m);
917 if (*m && !match(m, len, comment, commentLen))
929 QString str(tn_length / 2, Qt::Uninitialized);
930 qFromBigEndian<
char16_t>(tn, str.size(), str.data());
935 const char *comment,
int n)
const
937 if (context ==
nullptr)
939 if (sourceText ==
nullptr)
941 if (comment ==
nullptr)
948 goto searchDependencies;
951
952
953
955 quint16 hTableSize = read16(contextArray);
957 const uchar *c = contextArray + 2 + (g << 1);
958 quint16 off = read16(c);
962 c = contextArray + (2 + (hTableSize << 1) + (off << 1));
964 const uint contextLen = uint(strlen(context));
966 quint8 len = read8(c++);
969 if (match(c, len, context, contextLen))
975 numItems = offsetLength / (2 *
sizeof(quint32));
977 goto searchDependencies;
980 numerus = numerusHelper(n, numerusRulesArray, numerusRulesLength);
984 elfHash_continue(sourceText, h);
985 elfHash_continue(comment, h);
988 const uchar *start = offsetArray;
989 const uchar *end = start + ((numItems - 1) << 3);
990 while (start <= end) {
991 const uchar *middle = start + (((end - start) >> 4) << 3);
992 uint hash = read32(middle);
996 }
else if (hash < h) {
1005 while (start != offsetArray && read32(start) == read32(start - 8))
1008 while (start < offsetArray + offsetLength) {
1009 quint32 rh = read32(start);
1013 quint32 ro = read32(start);
1015 QString tn = getMessage(messageArray + ro, messageArray + messageLength, context,
1016 sourceText, comment, numerus);
1027 for (
const auto &translator : subTranslators) {
1028 QString tn = translator->translate(context, sourceText, comment, n);
1036
1037
1042 if (unmapPointer && unmapLength) {
1043#if defined(QT_USE_MMAP)
1046 munmap(unmapPointer, unmapLength);
1056 messageArray =
nullptr;
1057 contextArray =
nullptr;
1058 offsetArray =
nullptr;
1059 numerusRulesArray =
nullptr;
1065 subTranslators.clear();
1070 if (QCoreApplicationPrivate::isTranslatorInstalled(q))
1071 QCoreApplication::postEvent(QCoreApplication::instance(),
1072 new QEvent(QEvent::LanguageChange));
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095QString QTranslator::translate(
const char *context,
const char *sourceText,
const char *disambiguation,
1098 Q_D(
const QTranslator);
1102 if (!d->lock.tryLock())
1104 QString result = d->do_translate(context, sourceText, disambiguation, n);
1110
1111
1112bool QTranslator::isEmpty()
const
1114 Q_D(
const QTranslator);
1115 return !d->messageArray && !d->offsetArray && !d->contextArray
1116 && d->subTranslators.empty();
1120
1121
1122
1123
1124QString QTranslator::language()
const
1126 Q_D(
const QTranslator);
1131
1132
1133
1134
1135
1136
1137
1138
1139QString QTranslator::filePath()
const
1141 Q_D(
const QTranslator);
1147#include "moc_qtranslator.cpp"
bool do_load(const QString &filename, const QString &directory)
const uchar * contextArray
bool do_load(const uchar *data, qsizetype len, const QString &directory)
const uchar * messageArray
QString do_translate(const char *context, const char *sourceText, const char *comment, int n) const
const uchar * offsetArray
bool load_translation(const QStringList &languages, const QString &filename, const QString &prefix, const QString &directory, const QString &suffix)
std::unique_ptr< QResource > resource
std::vector< std::unique_ptr< QTranslator > > subTranslators
const uchar * numerusRulesArray
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
#define QStringLiteral(str)
static const int MagicLength
static QString getMessage(const uchar *m, const uchar *end, const char *context, const char *sourceText, const char *comment, uint numerus)
static quint32 read32(const uchar *data)
static void elfHash_continue(const char *name, uint &h)
static bool isValidNumerusRules(const uchar *rules, uint rulesSize)
static QString dotQmLiteral()
static uint elfHash(const char *name)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
static uint numerusHelper(int n, const uchar *rules, uint rulesSize)
static quint8 read8(const uchar *data)
static quint16 read16(const uchar *data)
static const uchar magic[MagicLength]
static void elfHash_finish(uint &h)