Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:critical reason:data-parser
++
++ #include "qicucodec_p.h"
++
++ #include "qtextcodec_p.h"
++ #include "qutfcodec_p.h"
++ #include "qlatincodec_p.h"
++ #include "qsimplecodec_p.h"
++ #include "qdebug.h"
++ #include <QtCore/qloggingcategory.h>
++
++ #include "unicode/ucnv.h"
++
++ #if QT_CONFIG(codecs)
++ #include "qtsciicodec_p.h"
++ #include "qisciicodec_p.h"
++ #endif
++
++ QT_BEGIN_NAMESPACE
++
++ Q_STATIC_LOGGING_CATEGORY(lcIcu, "qt.core5compat.qtextcodec.icu");
++
++ typedef QList<QTextCodec*>::ConstIterator TextCodecListConstIt;
++ typedef QList<QByteArray>::ConstIterator ByteArrayListConstIt;
++
++ Q_DECL_COLD_FUNCTION
++ static void warnOnLongInput()
++ {
++ qWarning(lcIcu, "Unable to allocate an output buffer of a proper size - the input"
++ " is too long. Pass the input data in smaller chunks instead.");
++ }
++
++ static void qIcuCodecStateFree(QTextCodec::ConverterState *state) noexcept
++ {
++ ucnv_close(static_cast<UConverter *>(state->d[0]));
++ }
++
++ bool qTextCodecNameMatch(const char *n, const char *h)
++ {
++ return ucnv_compareNames(n, h) == 0;
++ }
++
++ /* The list below is generated from http://www.iana.org/assignments/character-sets/
++ using the snippet of code below:
++
++ #include <QtCore>
++ #include <unicode/ucnv.h>
++
++ int main(int argc, char **argv)
++ {
++ QCoreApplication app(argc, argv);
++
++ QFile file("character-sets.txt");
++ file.open(QFile::ReadOnly);
++ QByteArray name;
++ int mib = -1;
++ QByteArray nameList;
++ int pos = 0;
++ while (!file.atEnd()) {
++ QByteArray s = file.readLine().trimmed();
++ if (s.isEmpty()) {
++ if (mib != -1) {
++ UErrorCode error = U_ZERO_ERROR;
++ const char *standard_name = ucnv_getStandardName(name, "MIME", &error);
++ if (U_FAILURE(error) || !standard_name) {
++ error = U_ZERO_ERROR;
++ standard_name = ucnv_getStandardName(name, "IANA", &error);
++ }
++ UConverter *conv = ucnv_open(standard_name, &error);
++ if (!U_FAILURE(error) && conv && standard_name) {
++ ucnv_close(conv);
++ printf(" { %d, %d },\n", mib, pos);
++ nameList += "\"";
++ nameList += standard_name;
++ nameList += "\\0\"\n";
++ pos += strlen(standard_name) + 1;
++ }
++ }
++ name = QByteArray();
++ mib = -1;
++ }
++ if (s.startsWith("Name: ")) {
++ name = s.mid(5).trimmed();
++ if (name.indexOf(' ') > 0)
++ name = name.left(name.indexOf(' '));
++ }
++ if (s.startsWith("MIBenum:"))
++ mib = s.mid(8).trimmed().toInt();
++ if (s.startsWith("Alias:") && s.contains("MIME")) {
++ name = s.mid(6).trimmed();
++ name = name.left(name.indexOf(' ')).trimmed();
++ }
++ }
++ qDebug() << nameList;
++ }
++ */
++
++ struct MibToName {
++ short mib;
++ short index;
++ };
++
++ static const MibToName mibToName[] = {
++ { 3, 0 },
++ { 4, 9 },
++ { 5, 20 },
++ { 6, 31 },
++ { 7, 42 },
++ { 8, 53 },
++ { 9, 64 },
++ { 10, 75 },
++ { 11, 86 },
++ { 12, 97 },
++ { 13, 108 },
++ { 16, 120 },
++ { 17, 134 },
++ { 18, 144 },
++ { 30, 151 },
++ { 36, 160 },
++ { 37, 167 },
++ { 38, 179 },
++ { 39, 186 },
++ { 40, 198 },
++ { 57, 212 },
++ { 81, 223 },
++ { 82, 234 },
++ { 84, 245 },
++ { 85, 256 },
++ { 104, 267 },
++ { 105, 279 },
++ { 106, 295 },
++ { 109, 301 },
++ { 110, 313 },
++ { 111, 325 },
++ { 113, 337 },
++ { 114, 341 },
++ { 1000, 349 },
++ { 1001, 356 },
++ { 1011, 363 },
++ { 1012, 368 },
++ { 1013, 374 },
++ { 1014, 383 },
++ { 1015, 392 },
++ { 1016, 399 },
++ { 1017, 406 },
++ { 1018, 413 },
++ { 1019, 422 },
++ { 1020, 431 },
++ { 2004, 438 },
++ { 2005, 448 },
++ { 2009, 472 },
++ { 2013, 479 },
++ { 2016, 486 },
++ { 2024, 495 },
++ { 2025, 505 },
++ { 2026, 512 },
++ { 2027, 517 },
++ { 2028, 527 },
++ { 2030, 534 },
++ { 2033, 541 },
++ { 2034, 548 },
++ { 2035, 555 },
++ { 2037, 562 },
++ { 2038, 569 },
++ { 2039, 576 },
++ { 2040, 583 },
++ { 2041, 590 },
++ { 2043, 597 },
++ { 2011, 604 },
++ { 2044, 611 },
++ { 2045, 618 },
++ { 2010, 624 },
++ { 2046, 631 },
++ { 2047, 638 },
++ { 2048, 645 },
++ { 2049, 652 },
++ { 2050, 659 },
++ { 2051, 666 },
++ { 2052, 673 },
++ { 2053, 680 },
++ { 2054, 687 },
++ { 2055, 694 },
++ { 2056, 701 },
++ { 2062, 708 },
++ { 2063, 715 },
++ { 2084, 723 },
++ { 2085, 730 },
++ { 2086, 741 },
++ { 2087, 748 },
++ { 2088, 755 },
++ { 2089, 762 },
++ { 2091, 771 },
++ { 2092, 780 },
++ { 2093, 789 },
++ { 2094, 798 },
++ { 2095, 807 },
++ { 2096, 816 },
++ { 2097, 825 },
++ { 2098, 834 },
++ { 2099, 843 },
++ { 2100, 852 },
++ { 2101, 861 },
++ { 2102, 872 },
++ { 2250, 880 },
++ { 2251, 893 },
++ { 2252, 906 },
++ { 2253, 919 },
++ { 2254, 932 },
++ { 2255, 945 },
++ { 2256, 958 },
++ { 2257, 971 },
++ { 2258, 984 },
++ { 2259, 997 },
++ };
++ int mibToNameSize = sizeof(mibToName)/sizeof(MibToName);
++
++ static const char mibToNameTable[] =
++ "US-ASCII\0"
++ "ISO-8859-1\0"
++ "ISO-8859-2\0"
++ "ISO-8859-3\0"
++ "ISO-8859-4\0"
++ "ISO-8859-5\0"
++ "ISO-8859-6\0"
++ "ISO-8859-7\0"
++ "ISO-8859-8\0"
++ "ISO-8859-9\0"
++ "ISO-8859-10\0"
++ "ISO-2022-JP-1\0"
++ "Shift_JIS\0"
++ "EUC-JP\0"
++ "US-ASCII\0"
++ "EUC-KR\0"
++ "ISO-2022-KR\0"
++ "EUC-KR\0"
++ "ISO-2022-JP\0"
++ "ISO-2022-JP-2\0"
++ "GB_2312-80\0"
++ "ISO-8859-6\0"
++ "ISO-8859-6\0"
++ "ISO-8859-8\0"
++ "ISO-8859-8\0"
++ "ISO-2022-CN\0"
++ "ISO-2022-CN-EXT\0"
++ "UTF-8\0"
++ "ISO-8859-13\0"
++ "ISO-8859-14\0"
++ "ISO-8859-15\0"
++ "GBK\0"
++ "GB18030\0"
++ "UTF-16\0"
++ "UTF-32\0"
++ "SCSU\0"
++ "UTF-7\0"
++ "UTF-16BE\0"
++ "UTF-16LE\0"
++ "UTF-16\0"
++ "CESU-8\0"
++ "UTF-32\0"
++ "UTF-32BE\0"
++ "UTF-32LE\0"
++ "BOCU-1\0"
++ "hp-roman8\0"
++ "Adobe-Standard-Encoding\0"
++ "IBM850\0"
++ "IBM862\0"
++ "IBM-Thai\0"
++ "Shift_JIS\0"
++ "GB2312\0"
++ "Big5\0"
++ "macintosh\0"
++ "IBM037\0"
++ "IBM273\0"
++ "IBM277\0"
++ "IBM278\0"
++ "IBM280\0"
++ "IBM284\0"
++ "IBM285\0"
++ "IBM290\0"
++ "IBM297\0"
++ "IBM420\0"
++ "IBM424\0"
++ "IBM437\0"
++ "IBM500\0"
++ "cp851\0"
++ "IBM852\0"
++ "IBM855\0"
++ "IBM857\0"
++ "IBM860\0"
++ "IBM861\0"
++ "IBM863\0"
++ "IBM864\0"
++ "IBM865\0"
++ "IBM868\0"
++ "IBM869\0"
++ "IBM870\0"
++ "IBM871\0"
++ "IBM918\0"
++ "IBM1026\0"
++ "KOI8-R\0"
++ "HZ-GB-2312\0"
++ "IBM866\0"
++ "IBM775\0"
++ "KOI8-U\0"
++ "IBM00858\0"
++ "IBM01140\0"
++ "IBM01141\0"
++ "IBM01142\0"
++ "IBM01143\0"
++ "IBM01144\0"
++ "IBM01145\0"
++ "IBM01146\0"
++ "IBM01147\0"
++ "IBM01148\0"
++ "IBM01149\0"
++ "Big5-HKSCS\0"
++ "IBM1047\0"
++ "windows-1250\0"
++ "windows-1251\0"
++ "windows-1252\0"
++ "windows-1253\0"
++ "windows-1254\0"
++ "windows-1255\0"
++ "windows-1256\0"
++ "windows-1257\0"
++ "windows-1258\0"
++ "TIS-620\0";
++
++ static QTextCodec *loadQtCodec(const char *name)
++ {
++ if (!strcmp(name, "UTF-8"))
++ return new QUtf8Codec;
++ if (!strcmp(name, "UTF-16"))
++ return new QUtf16Codec;
++ if (!strcmp(name, "ISO-8859-1"))
++ return new QLatin1Codec;
++ if (!strcmp(name, "UTF-16BE"))
++ return new QUtf16BECodec;
++ if (!strcmp(name, "UTF-16LE"))
++ return new QUtf16LECodec;
++ if (!strcmp(name, "UTF-32"))
++ return new QUtf32Codec;
++ if (!strcmp(name, "UTF-32BE"))
++ return new QUtf32BECodec;
++ if (!strcmp(name, "UTF-32LE"))
++ return new QUtf32LECodec;
++ if (!strcmp(name, "ISO-8859-16") || !strcmp(name, "latin10") || !strcmp(name, "iso-ir-226"))
++ return new QSimpleTextCodec(13 /* == 8859-16*/);
++ #if QT_CONFIG(codecs)
++ if (!strcmp(name, "TSCII"))
++ return new QTsciiCodec;
++ if (!qstrnicmp(name, "iscii", 5))
++ return QIsciiCodec::create(name);
++ #endif
++
++ return nullptr;
++ }
++
++ /// \threadsafe
++ QList<QByteArray> QIcuCodec::availableCodecs()
++ {
++ QList<QByteArray> codecs;
++ int n = ucnv_countAvailable();
++ for (int i = 0; i < n; ++i) {
++ const char *name = ucnv_getAvailableName(i);
++
++ UErrorCode error = U_ZERO_ERROR;
++ const char *standardName = ucnv_getStandardName(name, "MIME", &error);
++ if (U_FAILURE(error) || !standardName) {
++ error = U_ZERO_ERROR;
++ standardName = ucnv_getStandardName(name, "IANA", &error);
++ }
++ if (U_FAILURE(error))
++ continue;
++
++ error = U_ZERO_ERROR;
++ int ac = ucnv_countAliases(standardName, &error);
++ if (U_FAILURE(error))
++ continue;
++ for (int j = 0; j < ac; ++j) {
++ error = U_ZERO_ERROR;
++ const char *alias = ucnv_getAlias(standardName, j, &error);
++ if (!U_SUCCESS(error))
++ continue;
++ codecs += alias;
++ }
++ }
++
++ // handled by Qt and not in ICU:
++ codecs += "TSCII";
++
++ return codecs;
++ }
++
++ /// \threadsafe
++ QList<int> QIcuCodec::availableMibs()
++ {
++ QList<int> mibs;
++ mibs.reserve(mibToNameSize + 1);
++ for (int i = 0; i < mibToNameSize; ++i)
++ mibs += mibToName[i].mib;
++
++ // handled by Qt and not in ICU:
++ mibs += 2107; // TSCII
++
++ return mibs;
++ }
++
++ QTextCodec *QIcuCodec::defaultCodecUnlocked()
++ {
++ QTextCodecData *globalData = QTextCodecData::instance();
++ if (!globalData)
++ return nullptr;
++ QTextCodec *c = globalData->codecForLocale.loadAcquire();
++ if (c)
++ return c;
++
++ #if defined(QT_LOCALE_IS_UTF8)
++ const char *name = "UTF-8";
++ #else
++ const char *name = ucnv_getDefaultName();
++ #endif
++ c = codecForNameUnlocked(name);
++ globalData->codecForLocale.storeRelease(c);
++ return c;
++ }
++
++
++ QTextCodec *QIcuCodec::codecForNameUnlocked(const char *name)
++ {
++ // backwards compatibility with Qt 4.x
++ if (!qstrcmp(name, "CP949"))
++ name = "windows-949";
++ else if (!qstrcmp(name, "Apple Roman"))
++ name = "macintosh";
++ // these are broken data in ICU 4.4, and can't be resolved even though they are aliases to tis-620
++ if (!qstrcmp(name, "windows-874-2000")
++ || !qstrcmp(name, "windows-874")
++ || !qstrcmp(name, "MS874")
++ || !qstrcmp(name, "x-windows-874")
++ || !qstrcmp(name, "ISO 8859-11"))
++ name = "TIS-620";
++
++ UErrorCode error = U_ZERO_ERROR;
++ // MIME gives better default names
++ const char *standardName = ucnv_getStandardName(name, "MIME", &error);
++ if (U_FAILURE(error) || !standardName) {
++ error = U_ZERO_ERROR;
++ standardName = ucnv_getStandardName(name, "IANA", &error);
++ }
++ bool qt_only = false;
++ if (U_FAILURE(error) || !standardName) {
++ standardName = name;
++ qt_only = true;
++ } else {
++ // correct some issues where the ICU data set contains duplicated entries.
++ // Where this happens it's because one data set is a subset of another. We
++ // always use the larger data set.
++
++ if (qstrcmp(standardName, "GB2312") == 0 || qstrcmp(standardName, "GB_2312-80") == 0)
++ standardName = "GBK";
++ else if (qstrcmp(standardName, "KSC_5601") == 0 || qstrcmp(standardName, "EUC-KR") == 0 || qstrcmp(standardName, "cp1363") == 0)
++ standardName = "windows-949";
++ }
++
++ QTextCodecData *globalData = QTextCodecData::instance();
++ QTextCodecCache *cache = &globalData->codecCache;
++
++ QTextCodec *codec;
++ if (cache) {
++ codec = cache->value(standardName);
++ if (codec)
++ return codec;
++ }
++
++ for (TextCodecListConstIt it = globalData->allCodecs.constBegin(), cend = globalData->allCodecs.constEnd(); it != cend; ++it) {
++ QTextCodec *cursor = *it;
++ if (qTextCodecNameMatch(cursor->name().constData(), standardName)) {
++ if (cache)
++ cache->insert(standardName, cursor);
++ return cursor;
++ }
++ QList<QByteArray> aliases = cursor->aliases();
++ for (ByteArrayListConstIt ait = aliases.constBegin(), acend = aliases.constEnd(); ait != acend; ++ait) {
++ if (qTextCodecNameMatch(ait->constData(), standardName)) {
++ if (cache)
++ cache->insert(standardName, cursor);
++ return cursor;
++ }
++ }
++ }
++
++ QTextCodec *c = loadQtCodec(standardName);
++ if (c)
++ return c;
++
++ if (qt_only)
++ return nullptr;
++
++ // check whether there is really a converter for the name available.
++ UConverter *conv = ucnv_open(standardName, &error);
++ if (!conv) {
++ qDebug("codecForName: ucnv_open failed %s %s", standardName, u_errorName(error));
++ return nullptr;
++ }
++ //qDebug() << "QIcuCodec: Standard name for " << name << "is" << standardName;
++ ucnv_close(conv);
++
++
++ c = new QIcuCodec(standardName);
++ if (cache)
++ cache->insert(standardName, c);
++ return c;
++ }
++
++
++ QTextCodec *QIcuCodec::codecForMibUnlocked(int mib)
++ {
++ for (int i = 0; i < mibToNameSize; ++i) {
++ if (mibToName[i].mib == mib)
++ return codecForNameUnlocked(mibToNameTable + mibToName[i].index);
++ }
++
++ if (mib == 2107)
++ return codecForNameUnlocked("TSCII");
++
++ return nullptr;
++ }
++
++
++ QIcuCodec::QIcuCodec(const char *name)
++ : m_name(name)
++ {
++ }
++
++ QIcuCodec::~QIcuCodec()
++ {
++ }
++
++ /*!
++ \internal
++
++ Custom callback for the ICU from Unicode conversion. It's invoked when the
++ conversion from Unicode detects illegal or unrecognized character.
++
++ Assumes that context contains a pointer to QTextCodec::ConverterState
++ structure. Updates its invalid characters count and calls a default
++ callback, that replaces the invalid characters properly.
++ */
++ static void customFromUnicodeSubstitutionCallback(const void *context,
++ UConverterFromUnicodeArgs *fromUArgs,
++ const UChar *codeUnits,
++ int32_t length,
++ UChar32 codePoint,
++ UConverterCallbackReason reason,
++ UErrorCode *err)
++ {
++ auto *state = reinterpret_cast<QTextCodec::ConverterState *>(const_cast<void *>(context));
++ if (state)
++ state->invalidChars++;
++ // Call the default callback that replaces all illegal or unrecognized
++ // sequences with the substitute string
++ UCNV_FROM_U_CALLBACK_SUBSTITUTE(nullptr, fromUArgs, codeUnits, length, codePoint, reason, err);
++ }
++
++ UConverter *QIcuCodec::getConverter(QTextCodec::ConverterState *state) const
++ {
++ UConverter *conv = nullptr;
++ if (state) {
++ if (!state->d[0]) {
++ // first time
++ state->clearFn = qIcuCodecStateFree;
++ UErrorCode error = U_ZERO_ERROR;
++ state->d[0] = ucnv_open(m_name, &error);
++ ucnv_setSubstChars(static_cast<UConverter *>(state->d[0]),
++ state->flags & QTextCodec::ConvertInvalidToNull ? "\0" : "?", 1, &error);
++ if (U_FAILURE(error)) {
++ qDebug("getConverter(state) ucnv_open failed %s %s", m_name, u_errorName(error));
++ } else {
++ error = U_ZERO_ERROR;
++ ucnv_setFromUCallBack(static_cast<UConverter *>(state->d[0]),
++ customFromUnicodeSubstitutionCallback, state, nullptr,
++ nullptr, &error);
++ if (U_FAILURE(error)) {
++ qDebug("getConverter(state) failed to install custom callback. "
++ "canEncode() may report incorrect results.");
++ }
++ }
++ }
++ conv = static_cast<UConverter *>(state->d[0]);
++ }
++ if (!conv) {
++ // stateless conversion
++ UErrorCode error = U_ZERO_ERROR;
++ conv = ucnv_open(m_name, &error);
++ ucnv_setSubstChars(conv, "?", 1, &error);
++ if (U_FAILURE(error))
++ qDebug("getConverter(no state) ucnv_open failed %s %s", m_name, u_errorName(error));
++ }
++ return conv;
++ }
++
++ QString QIcuCodec::convertToUnicode(const char *chars, int length, QTextCodec::ConverterState *state) const
++ {
++ UConverter *conv = getConverter(state);
++
++ // ICU requires the input and output buffers to stay within INT_MAX bytes.
++ constexpr int MaxStringSize = (std::numeric_limits<int>::max)() / sizeof(QChar);
++
++ QString string;
++ if (length > MaxStringSize - 2) {
++ warnOnLongInput();
++ return string;
++ }
++
++ string.resize(length + 2);
++
++ const char *end = chars + length;
++ int convertedChars = 0;
++ while (1) {
++ UChar *uc = (UChar *)string.data();
++ UChar *ucEnd = uc + string.size();
++ uc += convertedChars;
++ UErrorCode error = U_ZERO_ERROR;
++ ucnv_toUnicode(conv,
++ &uc, ucEnd,
++ &chars, end,
++ nullptr, false, &error);
++ if (!U_SUCCESS(error) && error != U_BUFFER_OVERFLOW_ERROR) {
++ qDebug("convertToUnicode failed: %s", u_errorName(error));
++ break;
++ }
++ // flag the state if we have incomplete input
++ if (error == U_TRUNCATED_CHAR_FOUND)
++ state->remainingChars = 1;
++
++ convertedChars = uc - (UChar *)string.data();
++ if (chars >= end)
++ break;
++ // Increase the size, but keep in mind that ICU is limited by INT_MAX bytes
++ if (string.size() <= MaxStringSize / 2)
++ string.resize(string.size() * 2);
++ else
++ break;
++ }
++ string.resize(convertedChars);
++
++ if (!state)
++ ucnv_close(conv);
++ return string;
++ }
++
++
++ QByteArray QIcuCodec::convertFromUnicode(const QChar *unicode, int length, QTextCodec::ConverterState *state) const
++ {
++ UConverter *conv = getConverter(state);
++
++ QByteArray string;
++
++ // That was UCNV_GET_MAX_BYTES_FOR_STRING, but we want to do the calculation in
++ // int64, so that the result does not overflow
++ qint64 requiredLength = (qint64{length} + 10) * qint64{ucnv_getMaxCharSize(conv)};
++
++ // ICU requires the input and output buffers to stay within INT_MAX bytes.
++ constexpr int MaxBufferSize = (std::numeric_limits<int>::max)();
++ if (requiredLength > MaxBufferSize) {
++ warnOnLongInput();
++ return string;
++ }
++
++ string.resize(static_cast<QByteArray::size_type>(requiredLength));
++
++ const UChar *uc = (const UChar *)unicode;
++ const UChar *end = uc + length;
++ int convertedChars = 0;
++ while (1) {
++ char *ch = (char *)string.data();
++ char *chEnd = ch + string.size();
++ ch += convertedChars;
++ UErrorCode error = U_ZERO_ERROR;
++ ucnv_fromUnicode(conv,
++ &ch, chEnd,
++ &uc, end,
++ nullptr, false, &error);
++ if (!U_SUCCESS(error))
++ qDebug("convertFromUnicode failed: %s", u_errorName(error));
++ // flag the state if we have incomplete input
++ if (error == U_TRUNCATED_CHAR_FOUND)
++ state->remainingChars = 1;
++
++ convertedChars = ch - string.data();
++ if (uc >= end)
++ break;
++ // Increase the size, but keep in mind that the calculation can overflow,
++ // and that ICU is limited by INT_MAX
++ if (string.size() <= MaxBufferSize / 2)
++ string.resize(string.size() * 2);
++ else
++ break;
++ }
++ string.resize(convertedChars);
++
++ if (!state)
++ ucnv_close(conv);
++
++ return string;
++ }
++
++
++ QByteArray QIcuCodec::name() const
++ {
++ return m_name;
++ }
++
++
++ QList<QByteArray> QIcuCodec::aliases() const
++ {
++ UErrorCode error = U_ZERO_ERROR;
++
++ int n = ucnv_countAliases(m_name, &error);
++
++ QList<QByteArray> aliases;
++ for (int i = 0; i < n; ++i) {
++ const char *a = ucnv_getAlias(m_name, i, &error);
++ // skip the canonical name
++ if (!a || !qstrcmp(a, m_name))
++ continue;
++ aliases += a;
++ }
++
++ return aliases;
++ }
++
++
++ int QIcuCodec::mibEnum() const
++ {
++ for (int i = 0; i < mibToNameSize; ++i) {
++ if (qTextCodecNameMatch(m_name, (mibToNameTable + mibToName[i].index)))
++ return mibToName[i].mib;
++ }
++
++ return 0;
++ }
++
++ QT_END_NAMESPACE