📄 translator.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the Qt Linguist of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "translator.h"#include <qplatformdefs.h>#ifndef QT_NO_TRANSLATION#include <QFileInfo>#include <QString>#include <QCoreApplication>#include <QDataStream>#include <QFile>#include <QMap>#include <QtAlgorithms>#include <stdlib.h>/*$ mcookie3cb86418caef9c95cd211cbf60a1bddd$*/// magic number for the filestatic const int MagicLength = 16;static const uchar magic[MagicLength] = { 0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95, 0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd};static uint elfHash(const char * name){ const uchar *k; uint h = 0; uint g; if (name) { k = (const uchar *) name; while (*k) { h = (h << 4) + *k++; if ((g = (h & 0xf0000000)) != 0) h ^= g >> 24; h &= ~g; } } if (!h) h = 1; return h;}extern bool qt_detectRTLLanguage();class TranslatorPrivate{public: struct Offset { Offset() : h(0), o(0) { } Offset(const TranslatorMessage& m, int offset) : h(m.hash()), o(offset) { } bool operator<(const Offset &other) const { return (h != other.h) ? h < other.h : o < other.o; } bool operator==(const Offset &other) const { return h == other.h && o == other.o; } uint h; uint o; }; enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88 }; TranslatorPrivate(Translator *qq) : q(qq), unmapPointer(0), unmapLength(0) {} // Translator must finalize this before deallocating it Translator *q; // for mmap'ed files, this is what needs to be unmapped. char *unmapPointer; unsigned int unmapLength; // for squeezed but non-file data, this is what needs to be deleted QByteArray messageArray; QByteArray offsetArray; QByteArray contextArray;#ifndef QT_NO_TRANSLATION_BUILDER QMap<TranslatorMessage, void *> messages;#endif QByteArray numerusRules;#if 0 bool do_load(const uchar *data, int len);#endif};Translator::Translator(QObject * parent) : QObject(parent){ d = new TranslatorPrivate(this);}Translator::~Translator(){ clear(); delete d;}bool Translator::save(const QString & filename, SaveMode mode){ QFile file(filename); if (!file.open(QIODevice::WriteOnly)) return false; return save(&file, mode);}bool Translator::save(QIODevice *iod, SaveMode mode){ squeeze(mode); QDataStream s(iod); s.writeRawData((const char *)magic, MagicLength); quint8 tag; if (!d->offsetArray.isEmpty()) { tag = (quint8)TranslatorPrivate::Hashes; quint32 oas = (quint32)d->offsetArray.size(); s << tag << oas; s.writeRawData(d->offsetArray, oas); } if (!d->messageArray.isEmpty()) { tag = (quint8)TranslatorPrivate::Messages; quint32 mas = (quint32)d->messageArray.size(); s << tag << mas; s.writeRawData(d->messageArray, mas); } if (!d->contextArray.isEmpty()) { tag = (quint8)TranslatorPrivate::Contexts; quint32 cas = (quint32)d->contextArray.size(); s << tag << cas; s.writeRawData(d->contextArray, cas); } if (!d->numerusRules.isEmpty()) { quint32 nrs = d->numerusRules.size(); s << quint8(TranslatorPrivate::NumerusRules) << nrs; s.writeRawData(d->numerusRules.constData(), nrs); } return true;}void Translator::clear(){ if (d->unmapPointer && d->unmapLength) { delete [] d->unmapPointer; d->unmapPointer = 0; d->unmapLength = 0; } d->messageArray.clear(); d->offsetArray.clear(); d->contextArray.clear(); d->messages.clear(); QEvent ev(QEvent::LanguageChange); QCoreApplication::sendEvent(QCoreApplication::instance(), &ev);}void Translator::squeeze(SaveMode mode){ if (d->messages.isEmpty()) { if (mode == Stripped) unsqueeze(); else return; } QMap<TranslatorMessage, void *> messages = d->messages; clear(); QMap<TranslatorPrivate::Offset, void *> offsets; QDataStream ms(&d->messageArray, QIODevice::WriteOnly); QMap<TranslatorMessage, void *>::const_iterator it, next; int cpPrev = 0, cpNext = 0; for (it = messages.constBegin(); it != messages.constEnd(); ++it) { cpPrev = cpNext; next = it; ++next; if (next == messages.constEnd()) cpNext = 0; else cpNext = (int) it.key().commonPrefix(next.key()); offsets.insert(TranslatorPrivate::Offset(it.key(), ms.device()->pos()), (void *)0); it.key().write(ms, mode == Stripped, (TranslatorMessage::Prefix)qMax(cpPrev, cpNext + 1)); } QMap<TranslatorPrivate::Offset, void *>::Iterator offset; offset = offsets.begin(); QDataStream ds(&d->offsetArray, QIODevice::WriteOnly); while (offset != offsets.end()) { TranslatorPrivate::Offset k = offset.key(); ++offset; ds << (quint32)k.h << (quint32)k.o; } if (mode == Stripped) { QMap<QByteArray, int> contextSet; for (it = messages.constBegin(); it != messages.constEnd(); ++it) ++contextSet[it.key().context()]; quint16 hTableSize; if (contextSet.size() < 200) hTableSize = (contextSet.size() < 60) ? 151 : 503; else if (contextSet.size() < 2500) hTableSize = (contextSet.size() < 750) ? 1511 : 5003; else hTableSize = (contextSet.size() < 10000) ? 15013 : 3 * contextSet.size() / 2; QMultiMap<int, const char *> hashMap; QMap<QByteArray, int>::const_iterator c; for (c = contextSet.constBegin(); c != contextSet.constEnd(); ++c) hashMap.insert(elfHash(c.key()) % hTableSize, c.key()); /* The contexts found in this translator are stored in a hash table to provide fast lookup. The context array has the following format: quint16 hTableSize; quint16 hTable[hTableSize]; quint8 contextPool[...]; The context pool stores the contexts as Pascal strings: quint8 len; quint8 data[len]; Let's consider the look-up of context "FunnyDialog". A hash value between 0 and hTableSize - 1 is computed, say h. If hTable[h] is 0, "FunnyDialog" is not covered by this translator. Else, we check in the contextPool at offset 2 * hTable[h] to see if "FunnyDialog" is one of the contexts stored there, until we find it or we meet the empty string. */ d->contextArray.resize(2 + (hTableSize << 1)); QDataStream t(&d->contextArray, QIODevice::WriteOnly);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -