Revision control

++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "xt9ime.h"
++ #include "xt9callbacks.h"
++ #include "xt9languagemap.h"
++ #include "xt9dbfile.h"
++ #include <QStandardPaths>
++ #include <QDir>
++ #include <QLoggingCategory>
++ #include <QtVirtualKeyboard/qvirtualkeyboarddictionarymanager.h>
++
++ QT_BEGIN_NAMESPACE
++ namespace QtVirtualKeyboard {
++
++ Q_LOGGING_CATEGORY(lcXT9, "qt.virtualkeyboard.xt9")
++
++ Xt9Ime::Xt9Ime(Xt9RequestCallback *requestCallback, Xt9KeyboardGenerator::CodeConverter *codeConverter) :
++ _requestCallback(requestCallback),
++ codeConverter(codeConverter)
++ {
++ }
++
++ void Xt9Ime::sysInit()
++ {
++ if (!ldbManager)
++ ldbManager.reset(new Xt9LdbManager());
++ memset(&sWordSymbInfo, 0, sizeof(sWordSymbInfo));
++ memset(&sKdbInfo, 0, sizeof(sKdbInfo));
++ memset(&sSearchEngine, 0, sizeof(sSearchEngine));
++ XT9_API(ET9WordSymbInit, &sWordSymbInfo, 1, ET9Request, this);
++ XT9_API(ET9NAV_Init, &sSearchEngine, &sWordSymbInfo);
++ }
++
++ bool Xt9Ime::kdbInit(const QVariantMap &vkbLayout)
++ {
++ ET9STATUS eStatus;
++
++ keyboardGenerator.reset(new Xt9KeyboardGenerator(vkbLayout, codeConverter));
++
++ const ET9U32 dwFirstKdbNum = static_cast<ET9U32>(vkbLayout[Xt9KeyboardGenerator::PRIMARY_ID].toInt());
++
++ eStatus = XT9_API(ET9KDB_Init,
++ &sKdbInfo,
++ &sWordSymbInfo,
++ dwFirstKdbNum,
++ 0,
++ &ET9KDBLoad,
++ &ET9KDBRequest,
++ this);
++
++ return !eStatus;
++ }
++
++ void Xt9Ime::uninit()
++ {
++ clearInput();
++ keyboardGenerator.reset();
++ ldbManager->closeAll();
++ sysInit();
++ }
++
++ QString Xt9Ime::exactWord(int *wordCompLen)
++ {
++ ET9SimpleWord simpleWord;
++ ET9STATUS eStatus;
++
++ eStatus = XT9_API(ET9GetExactWord, &sWordSymbInfo, &simpleWord);
++ if (eStatus) {
++ if (wordCompLen)
++ *wordCompLen = 0;
++ return QString();
++ }
++
++ if (wordCompLen)
++ *wordCompLen = simpleWord.wCompLen;
++
++ return QString::fromUtf16(reinterpret_cast<const char16_t *>(simpleWord.sString), simpleWord.wLen);
++ }
++
++ bool Xt9Ime::hasActiveInput() const
++ {
++ return ET9HasActiveInput(&sWordSymbInfo);
++ }
++
++ QStringList Xt9Ime::buildSelectionList(int *defaultListIndex, unsigned short *gestureValue)
++ {
++ ET9STATUS eStatus = ET9STATUS_NONE;
++ return buildSelectionList(defaultListIndex, gestureValue, eStatus);
++ }
++
++ void Xt9Ime::cursorMoved()
++ {
++ XT9_API(ET9CursorMoved, &sWordSymbInfo, 1);
++ }
++
++ void Xt9Ime::clearInput()
++ {
++ XT9_API(ET9ClearAllSymbs, &sWordSymbInfo);
++ }
++
++ void Xt9Ime::setCapsLock()
++ {
++ XT9_API(ET9SetCapsLock, &sWordSymbInfo);
++ }
++
++ void Xt9Ime::setShift()
++ {
++ XT9_API(ET9SetShift, &sWordSymbInfo);
++ }
++
++ void Xt9Ime::setUnShift()
++ {
++ XT9_API(ET9SetUnShift, &sWordSymbInfo);
++ }
++
++ void Xt9Ime::setWorkingDirectory(const QString &workingDirectory)
++ {
++ QString dir = workingDirectory;
++ if (!workingDirectory.isEmpty() && !dir.endsWith(QLatin1Char('/')))
++ dir.append(QLatin1Char('/'));
++ dir = QDir::toNativeSeparators(dir);
++ XT9_API(ET9NAVCore_SetWorkingDirectory, &sSearchEngine, dir.toUtf8().constData());
++ }
++
++ bool Xt9Ime::indexExists(quint16 id)
++ {
++ ET9BOOL exists = 0;
++
++ XT9_API(ET9NAVCore_IndexExists, &sSearchEngine, id, &exists);
++
++ return exists != 0;
++ }
++
++ bool Xt9Ime::createIndex(quint16 id, quint32 contentInfo)
++ {
++ ET9STATUS eStatus;
++ ET9NAVTypeInfo sTypeInfo;
++
++ if (indexExists(id)) {
++ removeIndex(id);
++ }
++
++ eStatus = XT9_API(ET9NAVTypeInfo_Init, &sTypeInfo, id, ET9NAVNO_RECORD_KEY_LENGTH, 0, ET9NAVSTORE_DISPLAY_STR_IN_INDEX);
++ if (!eStatus) {
++ eStatus = XT9_API(ET9NAVCore_CreateIndex, &sSearchEngine, id, &sTypeInfo, 1, contentInfo, 0);
++ }
++
++ return !eStatus;
++ }
++
++ bool Xt9Ime::insertRecord(quint16 id, const QString &phrase, const QString &tokens)
++ {
++ ET9STATUS eStatus;
++ ET9NAVRecord sRecord;
++
++ eStatus = XT9_API(ET9NAVRecord_Init_NoKey, &sSearchEngine, &sRecord, id);
++ if (!eStatus) {
++ if (tokens.length() > 0) {
++ eStatus = XT9_API(ET9NAVRecord_AddField_Conversion, &sRecord,
++ static_cast<const ET9SYMB *>(tokens.utf16()),
++ static_cast<quint16>(tokens.length()),
++ static_cast<const ET9SYMB *>(phrase.utf16()),
++ static_cast<quint16>(phrase.length()),
++ ET9NAVMATCHLOGIC_ANY);
++ } else {
++ eStatus = XT9_API(ET9NAVRecord_AddField_16BIT, &sRecord,
++ static_cast<const ET9SYMB *>(phrase.utf16()),
++ static_cast<quint16>(phrase.length()),
++ ET9NAVMATCHLOGIC_ANY);
++ }
++
++ if (!eStatus) {
++ eStatus = XT9_API(ET9NAVCore_InsertRecord, &sSearchEngine, &sRecord);
++ }
++ }
++
++ return !eStatus;
++ }
++
++ void Xt9Ime::finalizeIndex(quint16 id)
++ {
++ XT9_API(ET9NAVCore_FinalizeIndex, &sSearchEngine, id);
++ }
++
++ void Xt9Ime::updateIndex(quint16 id, const QStringList &wordList)
++ {
++ createIndex(id);
++ for (const QString &word : wordList) {
++ insertRecord(id, word);
++ }
++ finalizeIndex(id);
++ }
++
++ void Xt9Ime::removeIndex(quint16 id)
++ {
++ XT9_API(ET9NAVCore_RemoveIndex, &sSearchEngine, id);
++ }
++
++ void Xt9Ime::removeAllIndexes()
++ {
++ XT9_API(ET9NAVCore_RemoveAllIndexes, &sSearchEngine);
++ }
++
++ void Xt9Ime::mountIndex(quint16 id)
++ {
++ XT9_API(ET9NAVCore_MountIndex, &sSearchEngine, id, ET9NAVMountProperty_ReadOnlyNoValidation);
++ }
++
++ void Xt9Ime::unmountIndex(quint16 id)
++ {
++ XT9_API(ET9NAVCore_UnmountIndex, &sSearchEngine, id);
++ }
++
++ ET9STATUS Xt9Ime::ldbReadData(ET9U32 dwLdbNum, ET9U8 *ET9FARDATA *ppbSrc, ET9U32 *pdwSizeInBytes)
++ {
++ const QLocale locale = Xt9LanguageMap::locale(dwLdbNum);
++ if (locale.language() == QLocale::AnyLanguage) {
++ return ET9STATUS_READ_DB_FAIL;
++ }
++
++ const void *data;
++ qint64 size;
++ if (!ldbManager->loadDictionary(locale, data, size)) {
++ return ET9STATUS_READ_DB_FAIL;
++ }
++
++ *ppbSrc = static_cast<ET9U8 *>(const_cast<void *>(data));
++ *pdwSizeInBytes = static_cast<ET9U32>(size);
++
++ return ET9STATUS_NONE;
++ }
++
++ ET9STATUS Xt9Ime::ET9Request(ET9WordSymbInfo *const pWordSymbInfo, ET9_Request *const pRequest)
++ {
++ return reinterpret_cast<Xt9Ime *>(pWordSymbInfo->pPublicExtension)->request(pRequest);
++ }
++
++ ET9STATUS Xt9Ime::request(ET9_Request *const pRequest)
++ {
++ #ifdef XT9_DEBUG
++ qCDebug(lcXT9) << "ET9Request, type =" << pRequest->eType;
++ #endif
++ return _requestCallback->request(pRequest);
++ }
++
++ ET9STATUS Xt9Ime::ET9KDBLoad(ET9KDBInfo *const pKdbInfo, const ET9U32 dwKdbNum, const ET9U16 wPageNum)
++ {
++ return reinterpret_cast<Xt9Ime *>(pKdbInfo->pPublicExtension)->kdbLoad(dwKdbNum, wPageNum);
++ }
++
++ ET9STATUS Xt9Ime::kdbLoad(const ET9U32 dwKdbNum, const ET9U16 wPageNum)
++ {
++ Q_UNUSED(dwKdbNum)
++
++ ET9STATUS eStatus;
++ ET9UINT nErrorLine = 0;
++
++ if (keyboardGenerator->vkbLayout.isEmpty()) {
++ qCWarning(lcXT9) << "Keyboard layout is not set.";
++ return ET9STATUS_READ_DB_FAIL;
++ }
++
++ QByteArray xmlData = keyboardGenerator->createXmlLayout();
++ if (xmlData.isEmpty()) {
++ qCWarning(lcXT9) << "Failed to create xml layout.";
++ return ET9STATUS_READ_DB_FAIL;
++ }
++
++ eStatus = XT9_API(ET9KDB_Load_XmlKDB,
++ &sKdbInfo,
++ static_cast<ET9U16>(qRound(keyboardGenerator->layoutWidth)),
++ static_cast<ET9U16>(qRound(keyboardGenerator->layoutHeight)),
++ wPageNum,
++ reinterpret_cast<const ET9U8 *>(xmlData.constData()),
++ static_cast<ET9U32>(xmlData.size()),
++ nullptr,
++ nullptr,
++ &nErrorLine);
++
++ if (eStatus) {
++ qCWarning(lcXT9).nospace() << "Failed to load xml layout, status: " << eStatus << ", line: " << nErrorLine;
++ qCWarning(lcXT9).nospace().noquote() << xmlData.constData();
++ }
++
++ return eStatus;
++ }
++
++ ET9STATUS Xt9Ime::ET9KDBRequest(ET9KDBInfo *const pKDBInfo, ET9WordSymbInfo *const pWordSymbInfo, ET9KDB_Request *const pET9KDB_Request)
++ {
++ Q_UNUSED(pWordSymbInfo)
++ return reinterpret_cast<Xt9Ime *>(pKDBInfo->pPublicExtension)->kdbRequest(pET9KDB_Request);
++ }
++
++ ET9STATUS Xt9Ime::kdbRequest(ET9KDB_Request *const pET9KDB_Request)
++ {
++ #ifdef XT9_DEBUG
++ qCDebug(lcXT9) << "ET9KDB_Request, type =" << pET9KDB_Request->eType;
++ #endif
++ return ET9STATUS_NONE;
++ }
++
++ } // namespace QtVirtualKeyboard
++ QT_END_NAMESPACE