Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
		}
	}
Esempio n. 4
0
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;
}