bool KviLocale::findCatalogue(QString & szBuffer, const QString & szName, const QString & szLocaleDir) { KviCString szLocale = g_szLang; QString szLocDir = szLocaleDir; KviQString::ensureLastCharIs(szLocDir, KVI_PATH_SEPARATOR_CHAR); szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr()); if(KviFileUtils::fileExists(szBuffer)) return true; if(szLocale.findFirstIdx('.') != -1) { // things like en_GB.utf8 // kill them szLocale.cutFromFirst('.'); szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr()); if(KviFileUtils::fileExists(szBuffer)) return true; } if(szLocale.findFirstIdx('@') != -1) { // things like @euro ? // kill them szLocale.cutFromFirst('@'); szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr()); if(KviFileUtils::fileExists(szBuffer)) return true; } if(szLocale.findFirstIdx('_') != -1) { // things like en_GB // kill them szLocale.cutFromFirst('_'); szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr()); if(KviFileUtils::fileExists(szBuffer)) return true; } // try the lower case version too szLocale.toLower(); szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr()); if(KviFileUtils::fileExists(szBuffer)) return true; return false; }
QTextCodec * KviLocale::codecForName(const char * pcName) { KviCString szTmp = pcName; bool bSendUtf8; int iIdx = szTmp.findFirstIdx('['); if(iIdx != -1) { // Might be a composite codec: either UTF-8 [child codec] or child codec [UTF-8] KviSmartTextCodec * pCodec = g_pSmartCodecDict->find(pcName); if(pCodec) return pCodec; // got cached copy if(kvi_strEqualCIN("UTF-8 [", pcName, 7)) { // Likely a smart codec that sends UTF-8 szTmp.replaceAll("UTF-8 [", ""); szTmp.replaceAll("]", ""); bSendUtf8 = true; } else { // Likely a smart codec that sends child encoding ? szTmp.cutFromFirst(' '); bSendUtf8 = false; } QTextCodec * pChildCodec = QTextCodec::codecForName(szTmp.ptr()); if(pChildCodec) { pCodec = new KviSmartTextCodec(pcName, pChildCodec, bSendUtf8); if(pCodec->ok()) { g_pSmartCodecDict->replace(pcName, pCodec); return pCodec; } delete pCodec; } else { // The name of the child codec was invalid: can't create such a smart codec. // We probably screwed up the guess above related to the [ char. // This code path is also triggered by the yircfuzzer by specifying completely invalid codec names. } } return QTextCodec::codecForName(pcName); }
void KviVariantTableItem::setContentFromEditor(QWidget * w) { switch(m_property.type()) { case QVariant::String: m_property = QVariant(((QLineEdit *)w)->text()); break; case QVariant::Int: m_property = QVariant(((QLineEdit *)w)->text().toInt()); break; case QVariant::UInt: m_property = QVariant(((QLineEdit *)w)->text().toUInt()); break; case QVariant::Bool: m_property = QVariant(((QComboBox *)w)->currentItem(),1); break; case QVariant::Color: m_property.asColor().setNamedColor(((QLineEdit *)w)->text()); break; case QVariant::Font: { KviCString txt = ((QComboBox *)w)->currentText(); if(txt.hasData()) { KviCString fam = txt; fam.cutFromFirst(',',true); fam.trimmed(); KviCString psz = txt; psz.cutToFirst(',',true); psz.trimmed(); bool bOk; unsigned int uSize = psz.toUInt(&bOk); if(!bOk)uSize = 12; m_property = QVariant(QFont(fam.ptr(),uSize)); } } break; default: break; } }
KviLocale::KviLocale(QApplication * pApp, const QString & szLocaleDir, const QString & szForceLocaleDir) { m_pApp = pApp; // first of all try to find out the current locale QString szLangFile = QString("%1/%2").arg(szForceLocaleDir, KVI_FORCE_LOCALE_FILE_NAME); if(KviFileUtils::fileExists(szLangFile)) KviFileUtils::readFile(szLangFile, g_szLang); if(g_szLang.isEmpty()) g_szLang = KviEnvironment::getVariable("KVIRC_LANG"); #ifdef COMPILE_KDE_SUPPORT if(g_szLang.isEmpty()) g_szLang = KviEnvironment::getVariable("KDE_LANG"); #endif //COMPILE_KDE_SUPPORT if(g_szLang.isEmpty()) g_szLang = KviEnvironment::getVariable("LC_MESSAGES"); if(g_szLang.isEmpty()) g_szLang = KviEnvironment::getVariable("LANG"); if(g_szLang.isEmpty()) g_szLang = QLocale::system().name(); if(g_szLang.isEmpty()) g_szLang = "en"; g_szLang = g_szLang.trimmed(); g_szDefaultLocalePath = szLocaleDir; // the main catalogue is supposed to be kvirc_<language>.mo g_pMainCatalogue = new KviMessageCatalogue(); // the catalogue dict g_pCatalogueDict = new KviPointerHashTable<const char *, KviMessageCatalogue>; g_pCatalogueDict->setAutoDelete(true); // the smart codec dict g_pSmartCodecDict = new KviPointerHashTable<const char *, KviSmartTextCodec>; // the Qt docs explicitly state that we shouldn't delete // the codecs by ourselves... g_pSmartCodecDict->setAutoDelete(false); if(!g_szLang.isEmpty()) { // ensure Qt will use the right locale when formatting dates, numbers, .. // Note: Qt will use the system() locale anyway, we need to construct an empty QLocale() // to get it use our specified locale. QLocale::setDefault(QLocale(g_szLang)); QString szBuffer; if(findCatalogue(szBuffer, "kvirc", szLocaleDir)) { g_pMainCatalogue->load(szBuffer); g_pTranslator = new KviTranslator(m_pApp); m_pApp->installTranslator(g_pTranslator); } else { KviCString szTmp = g_szLang; szTmp.cutFromFirst('.'); szTmp.cutFromFirst('_'); szTmp.cutFromFirst('@'); szTmp.toLower(); if(!(kvi_strEqualCI(szTmp.ptr(), "en") || kvi_strEqualCI(szTmp.ptr(), "c") || kvi_strEqualCI(szTmp.ptr(), "us") || kvi_strEqualCI(szTmp.ptr(), "gb") || kvi_strEqualCI(szTmp.ptr(), "posix"))) { // FIXME: THIS IS NO LONGER VALID!!! qDebug("Can't find the catalogue for locale \"%s\" (%s)", g_szLang.toUtf8().data(), szTmp.ptr()); qDebug("There is no such translation or the $LANG variable was incorrectly set"); qDebug("You can use $KVIRC_LANG to override the catalogue name"); qDebug("For example you can set KVIRC_LANG to it_IT to force usage of the it.mo catalogue"); } } } }
bool KviMessageCatalogue::load(const QString & szName) { QString szCatalogueFile(szName); // Try to load the header KviFile f(szCatalogueFile); if(!f.open(QFile::ReadOnly)) { qDebug("[KviLocale]: Failed to open the messages file %s: probably doesn't exist",szCatalogueFile.toUtf8().data()); return false; } GnuMoFileHeader hdr; if(f.read((char *)&hdr,sizeof(GnuMoFileHeader)) < (int)sizeof(GnuMoFileHeader)) { qDebug("KviLocale: Failed to read header of %s",szCatalogueFile.toUtf8().data()); f.close(); return false; } bool bMustSwap = false; if(hdr.magic != KVI_LOCALE_MAGIC) { if(hdr.magic == KVI_LOCALE_MAGIC_SWAPPED) { qDebug("KviLocale: Swapped magic for file %s: swapping data too",szCatalogueFile.toUtf8().data()); bMustSwap = true; } else { qDebug("KviLocale: Bad locale magic for file %s: not a *.mo file ?",szCatalogueFile.toUtf8().data()); f.close(); return false; } } if(KVI_SWAP_IF_NEEDED(bMustSwap,hdr.revision) != MO_REVISION_NUMBER) { qDebug("KviLocale: Invalid *.mo file revision number for file %s",szCatalogueFile.toUtf8().data()); f.close(); return false; } int iStringsNum = KVI_SWAP_IF_NEEDED(bMustSwap,hdr.nstrings); if(iStringsNum <= 0) { qDebug("KviLocale: No translated messages found in file %s",szCatalogueFile.toUtf8().data()); f.close(); return false; } if(iStringsNum >= 9972) { qDebug("Number of strings too big...sure that it is a KVIrc catalog file ?"); iStringsNum = 9972; } // return back f.seek(0); unsigned int uSize = f.size(); char * pcBuffer = (char *)KviMemory::allocate(uSize); // FIXME: maybe read it in blocks eh ? if(f.read(pcBuffer,uSize) < (int)uSize) { qDebug("KviLocale: Error while reading the translation file %s",szCatalogueFile.toUtf8().data()); KviMemory::free(pcBuffer); f.close(); return false; } // Check for broken *.mo files if(uSize < (24 + (sizeof(GnuMoStringDescriptor) * iStringsNum))) { qDebug("KviLocale: Broken translation file %s (too small for all descriptors)",szCatalogueFile.toUtf8().data()); KviMemory::free(pcBuffer); f.close(); return false; } GnuMoStringDescriptor * pOrigDescriptor = (GnuMoStringDescriptor *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.orig_tab_offset)); GnuMoStringDescriptor * pTransDescriptor = (GnuMoStringDescriptor *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.trans_tab_offset)); // Check again for broken *.mo files int iExpectedFileSize = KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[iStringsNum - 1].offset) + KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[iStringsNum - 1].length); if(uSize < (unsigned int)iExpectedFileSize) { qDebug("KviLocale: Broken translation file %s (too small for all the message strings)",szCatalogueFile.toUtf8().data()); KviMemory::free(pcBuffer); f.close(); return false; } // Ok...we can run now int iDictSize = kvi_getFirstBiggerPrime(iStringsNum); if(m_pMessages) delete m_pMessages; m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(iDictSize,true,false); // dictSize, case sensitive, don't copy keys m_pMessages->setAutoDelete(true); KviCString szHeader; for(int i = 0; i < iStringsNum; i++) { // FIXME: "Check for NULL inside strings here ?" //qDebug("original seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].offset), // KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].length)); //qDebug("translated seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].offset), // KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].length)); KviTranslationEntry * e = new KviTranslationEntry( (char *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].offset)), KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].length), (char *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].offset)), KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].length)); // In some (or all?) *.mo files the first string // is zero bytes long and the translated one contains // information about the translation if(e->m_szKey.len() == 0) { szHeader = e->m_szEncodedTranslation; delete e; continue; } m_pMessages->insert(e->m_szKey.ptr(),e); } KviMemory::free(pcBuffer); f.close(); m_pTextCodec = 0; // find out the text encoding, if possible if(szHeader.hasData()) { // find "charset=*\n" int iIdx = szHeader.findFirstIdx("charset="); if(iIdx != -1) { szHeader.cutLeft(iIdx + 8); szHeader.cutFromFirst('\n'); szHeader.trim(); m_pTextCodec = KviLocale::instance()->codecForName(szHeader.ptr()); if(!m_pTextCodec) { qDebug("Can't find the codec for charset=%s",szHeader.ptr()); qDebug("Falling back to codecForLocale()"); m_pTextCodec = QTextCodec::codecForLocale(); } } } if(!m_pTextCodec) { qDebug("The message catalogue does not have a \"charset\" header"); qDebug("Assuming utf8"); // FIXME: or codecForLocale() ? m_pTextCodec = QTextCodec::codecForName("UTF-8"); } return true; }