VirtualBox

Changeset 90828 in vbox for trunk/src/VBox/Main/src-all


Ignore:
Timestamp:
Aug 24, 2021 9:44:46 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
146463
Message:

Main: bugref:1909: Added API localization

Location:
trunk/src/VBox/Main/src-all
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-all/QMTranslatorImpl.cpp

    r85212 r90828  
    2323#include <iprt/file.h>
    2424#include <iprt/asm.h>
     25#include <iprt/string.h>
     26#include <iprt/strcache.h>
    2527#include <VBox/com/string.h>
    2628#include <VBox/log.h>
     
    4749class QMBytesStream
    4850{
    49     size_t m_cbSize;
     51    size_t         m_cbSize;
    5052    const uint8_t * const m_dataStart;
    5153    const uint8_t *m_iter;
    5254    const uint8_t *m_end;
    53 
    54     /* Function stub for transform method */
    55     static uint16_t func_BE2H_U16(uint16_t value)
    56     {
    57         return RT_BE2H_U16(value);
    58     }
    5955
    6056public:
     
    9490        uint32_t size = read32();
    9591        checkSize(size);
    96         if (size & 1) throw QMException("Incorrect string size");
    97         std::vector<uint16_t> wstr;
    98         wstr.reserve(size / 2);
    99 
    100         /* We cannot convert to host endianess without copying the data
    101          * since the file might be mapped to the memory and any memory
    102          * change will lead to the change of the file. */
    103         std::transform(reinterpret_cast<const uint16_t *>(m_iter),
    104                        reinterpret_cast<const uint16_t *>(m_iter + size),
    105                        std::back_inserter(wstr),
    106                        func_BE2H_U16);
     92        if (size & 1)
     93            throw QMException("Incorrect string size");
     94
     95        /* UTF-16 can encode up to codepoint U+10ffff, which UTF-8 needs 4 bytes
     96           to encode, so reserve twice the size plus a terminator for the result. */
     97        com::Utf8Str result;
     98        result.reserve(size * 2 + 1);
     99        char *pszStr = result.mutableRaw();
     100        int rc = RTUtf16BigToUtf8Ex((PCRTUTF16)m_iter, size >> 1, &pszStr, result.capacity(), NULL);
     101        if (RT_SUCCESS(rc))
     102            result.jolt();
     103        else
     104            throw QMException("Translation from UTF-16 to UTF-8 failed");
     105
    107106        m_iter += size;
    108         return com::Utf8Str((CBSTR) &wstr.front(), wstr.size());
    109     }
    110 
    111     /** Reads string in one-byte encoding.
    112      * The string is assumed to be in ISO-8859-1 encoding */
     107        return result;
     108    }
     109
     110    /**
     111     *  Reads a string, forcing UTF-8 encoding.
     112     */
    113113    inline com::Utf8Str readString()
    114114    {
    115115        uint32_t size = read32();
    116116        checkSize(size);
     117
    117118        com::Utf8Str result(reinterpret_cast<const char *>(m_iter), size);
     119        if (size > 0)
     120        {
     121            RTStrPurgeEncoding(result.mutableRaw());
     122            result.jolt();
     123        }
     124
    118125        m_iter += size;
    119126        return result;
     127    }
     128
     129    /**
     130     *  Reads memory block
     131     *  Returns number of bytes read
     132     */
     133    inline uint32_t read(char *bBuf, uint32_t cbSize)
     134    {
     135        if (!bBuf || !cbSize)
     136            return 0;
     137        cbSize = RT_MIN(cbSize, (uint32_t)(m_end - m_iter));
     138        memcpy(bBuf, m_iter, cbSize);
     139        m_iter += cbSize;
     140        return cbSize;
    120141    }
    121142
     
    148169    {
    149170        size_t cbLeft = (size_t)(m_end - m_iter);
    150         if (cbLeft <= offSkip)
     171        if (cbLeft >= offSkip)
    151172            m_iter += offSkip;
    152173        else
     
    166187class QMTranslator_Impl
    167188{
    168     struct QMMessage
     189    /** Used while parsing */
     190    struct QMMessageParse
    169191    {
    170192        /* Everything is in UTF-8 */
     193        std::vector<com::Utf8Str> astrTranslations;
    171194        com::Utf8Str strContext;
    172         com::Utf8Str strTranslation;
    173195        com::Utf8Str strComment;
    174196        com::Utf8Str strSource;
    175         uint32_t     hash;
    176         QMMessage() : hash(0) {}
     197
     198        QMMessageParse() {}
     199    };
     200
     201    struct QMMessage
     202    {
     203        const char *pszContext;
     204        const char *pszSource;
     205        const char *pszComment;
     206        std::vector<const char *> vecTranslations;
     207        uint32_t    hash;
     208
     209        QMMessage() : pszContext(NULL), pszSource(NULL), pszComment(NULL), hash(0)
     210        {}
     211
     212        QMMessage(RTSTRCACHE hStrCache, const QMMessageParse &rSrc)
     213            : pszContext(addStr(hStrCache, rSrc.strContext))
     214            , pszSource(addStr(hStrCache, rSrc.strSource))
     215            , pszComment(addStr(hStrCache, rSrc.strComment))
     216            , hash(RTStrHash1(pszSource))
     217        {
     218            for (size_t i = 0; i < rSrc.astrTranslations.size(); i++)
     219                vecTranslations.push_back(addStr(hStrCache, rSrc.astrTranslations[i]));
     220        }
     221
     222        /** Helper. */
     223        static const char *addStr(RTSTRCACHE hStrCache, const com::Utf8Str &rSrc)
     224        {
     225            if (rSrc.isNotEmpty())
     226            {
     227                const char *psz = RTStrCacheEnterN(hStrCache, rSrc.c_str(), rSrc.length());
     228                if (RT_LIKELY(psz))
     229                    return psz;
     230                throw std::bad_alloc();
     231            }
     232            return NULL;
     233        }
     234
    177235    };
    178236
     
    182240        uint32_t offset;
    183241
    184         HashOffset(uint32_t _hash = 0, uint32_t _offs = 0) : hash(_hash), offset(_offs) {}
     242        HashOffset(uint32_t a_hash = 0, uint32_t a_offs = 0) : hash(a_hash), offset(a_offs) {}
    185243
    186244        bool operator<(const HashOffset &obj) const
     
    194252    typedef QMHashSet::const_iterator QMHashSetConstIter;
    195253    typedef std::vector<QMMessage> QMMessageArray;
    196 
    197     QMHashSet m_hashSet;
     254    typedef std::vector<uint8_t> QMByteArray;
     255
     256    QMHashSet      m_hashSet;
    198257    QMMessageArray m_messageArray;
     258    QMByteArray    m_pluralRules;
    199259
    200260public:
    201261
    202262    QMTranslator_Impl() {}
     263
     264    enum PluralOpCodes
     265    {
     266        Pl_Eq          = 0x01,
     267        Pl_Lt          = 0x02,
     268        Pl_Leq         = 0x03,
     269        Pl_Between     = 0x04,
     270
     271        Pl_OpMask      = 0x07,
     272
     273        Pl_Not         = 0x08,
     274        Pl_Mod10       = 0x10,
     275        Pl_Mod100      = 0x20,
     276        Pl_Lead1000    = 0x40,
     277
     278        Pl_And         = 0xFD,
     279        Pl_Or          = 0xFE,
     280        Pl_NewRule     = 0xFF,
     281
     282        Pl_LMask       = 0x80,
     283    };
     284
     285    /*
     286     * Rules format:
     287     * <O><2>[<3>][<&&><O><2>[<3>]]...[<||><O><2>[<3>][<&&><O><2>[<3>]]...]...[<New><O>...]...
     288     * where:
     289     *    <O> - OpCode
     290     *    <2> - Second operand
     291     *    <3> - Third operand
     292     *    <&&> - 'And' operation
     293     *    <||> - 'Or' operation
     294     *    <New> - Start of rule for next plural form
     295     * Rules are ordered by plural forms, i.e:
     296     *   <rule for first form (i.e. single)><New><rule for next form>...
     297     */
     298    bool checkPlural(const QMByteArray &aRules) const
     299    {
     300        if (aRules.empty())
     301            return true;
     302
     303        uint32_t iPos = 0;
     304        do {
     305            uint8_t bOpCode = aRules[iPos];
     306
     307            /* Invalid place of And/Or/NewRule */
     308            if (bOpCode & Pl_LMask)
     309                return false;
     310
     311            /* 2nd operand */
     312            iPos++;
     313
     314            /* 2nd operand missing */
     315            if (iPos == aRules.size())
     316                return false;
     317
     318            /* Invalid OpCode */
     319            if ((bOpCode & Pl_OpMask) == 0)
     320                return false;
     321
     322            if ((bOpCode & Pl_OpMask) == Pl_Between)
     323            {
     324                /* 3rd operand */
     325                iPos++;
     326
     327                /* 3rd operand missing */
     328                if (iPos == aRules.size())
     329                    return false;
     330            }
     331
     332            /* And/Or/NewRule */
     333            iPos++;
     334
     335            /* All rules checked */
     336            if (iPos == aRules.size())
     337                return true;
     338
     339        } while (   (   (aRules[iPos] == Pl_And)
     340                     || (aRules[iPos] == Pl_Or)
     341                     || (aRules[iPos] == Pl_NewRule))
     342                 && ++iPos != aRules.size());
     343
     344        return false;
     345    }
     346
     347    int plural(int aNum) const
     348    {
     349        if (aNum < 1 || m_pluralRules.empty())
     350            return 0;
     351
     352        int  iPluralNumber = 0;
     353        uint32_t iPos = 0;
     354
     355        /* Rules loop */
     356        for (;;)
     357        {
     358            bool fOr = false;
     359            /* 'Or' loop */
     360            for (;;)
     361            {
     362                bool fAnd = true;
     363                /* 'And' loop */
     364                for (;;)
     365                {
     366                    int iOpCode = m_pluralRules[iPos++];
     367                    int iOpLeft = aNum;
     368                    if (iOpCode & Pl_Mod10)
     369                        iOpLeft %= 10;
     370                    else if (iOpCode & Pl_Mod100)
     371                        iOpLeft %= 100;
     372                    else if (iOpLeft & Pl_Lead1000)
     373                    {
     374                        while (iOpLeft >= 1000)
     375                            iOpLeft /= 1000;
     376                    }
     377                    int iOpRight = m_pluralRules[iPos++];
     378                    int iOp = iOpCode & Pl_OpMask;
     379                    int iOpRight1 = 0;
     380                    if (iOp == Pl_Between)
     381                        iOpRight1 = m_pluralRules[iPos++];
     382
     383                    bool fResult =    (iOp == Pl_Eq      && iOpLeft == iOpRight)
     384                            || (iOp == Pl_Lt      && iOpLeft <  iOpRight)
     385                            || (iOp == Pl_Leq     && iOpLeft <= iOpRight)
     386                            || (iOp == Pl_Between && iOpLeft >= iOpRight && iOpLeft <= iOpRight1);
     387                    if (iOpCode & Pl_Not)
     388                        fResult = !fResult;
     389
     390                    fAnd = fAnd && fResult;
     391                    if (iPos == m_pluralRules.size() || m_pluralRules[iPos] != Pl_And)
     392                        break;
     393                    iPos++;
     394                }
     395                fOr = fOr || fAnd;
     396                if (iPos == m_pluralRules.size() || m_pluralRules[iPos] != Pl_Or)
     397                    break;
     398                iPos++;
     399            }
     400            if (fOr)
     401                return iPluralNumber;
     402
     403            /* Qt returns last plural number if none of rules are match. */
     404            iPluralNumber++;
     405
     406            if (iPos >= m_pluralRules.size())
     407                return iPluralNumber;
     408
     409            iPos++; // Skip Pl_NewRule
     410        }
     411    }
    203412
    204413    const char *translate(const char *pszContext,
    205414                          const char *pszSource,
    206                           const char *pszDisamb) const
     415                          const char *pszDisamb,
     416                          const int   aNum) const
    207417    {
    208418        QMHashSetConstIter iter;
    209419        QMHashSetConstIter lowerIter, upperIter;
    210420
    211         do {
    212             uint32_t hash = calculateHash(pszSource, pszDisamb);
    213             lowerIter = m_hashSet.lower_bound(HashOffset(hash, 0));
    214             upperIter = m_hashSet.upper_bound(HashOffset(hash, UINT32_MAX));
    215 
     421        /* As turned out, comments (pszDisamb) are not kept always in result qm file
     422         * Therefore, exclude them from the hash */
     423        uint32_t hash = RTStrHash1(pszSource);
     424        lowerIter = m_hashSet.lower_bound(HashOffset(hash, 0));
     425        upperIter = m_hashSet.upper_bound(HashOffset(hash, UINT32_MAX));
     426
     427        /*
     428         * Check different combinations with and without context and
     429         * disambiguation. This can help us to find the translation even
     430         * if context or disambiguation are not know or properly defined.
     431         */
     432        const char *apszCtx[]    = {pszContext, pszContext, NULL,      NULL};
     433        const char *apszDisabm[] = {pszDisamb,  NULL,       pszDisamb, NULL};
     434        AssertCompile(RT_ELEMENTS(apszCtx) == RT_ELEMENTS(apszDisabm));
     435
     436        for (size_t i = 0; i < RT_ELEMENTS(apszCtx); ++i)
     437        {
    216438            for (iter = lowerIter; iter != upperIter; ++iter)
    217439            {
    218440                const QMMessage &message = m_messageArray[iter->offset];
    219                 if ((!pszContext || !*pszContext || message.strContext == pszContext) &&
    220                     message.strSource == pszSource &&
    221                     ((pszDisamb && !*pszDisamb) || message.strComment == pszDisamb))
    222                     break;
     441                if (   RTStrCmp(message.pszSource, pszSource) == 0
     442                    && (!apszCtx[i]     || !*apszCtx[i]     || RTStrCmp(message.pszContext, apszCtx[i]) == 0)
     443                    && (!apszDisabm[i]  || !*apszDisabm[i]  || RTStrCmp(message.pszComment, apszDisabm[i]) == 0 ))
     444                {
     445                    const std::vector<const char *> &vecTranslations = m_messageArray[iter->offset].vecTranslations;
     446                    size_t idxPlural = plural(aNum);
     447                    return vecTranslations[RT_MIN(idxPlural, vecTranslations.size() - 1)];
     448                }
    223449            }
    224 
    225             /* Try without disambiguating comment if it isn't empty */
    226             if (pszDisamb)
    227             {
    228                 if (!*pszDisamb) pszDisamb = 0;
    229                 else pszDisamb = "";
    230             }
    231 
    232         } while (iter == upperIter && pszDisamb);
    233 
    234         return (iter != upperIter ? m_messageArray[iter->offset].strTranslation.c_str() : "");
    235     }
    236 
    237     void load(QMBytesStream &stream)
     450        }
     451
     452        return pszSource;
     453    }
     454
     455    void load(QMBytesStream &stream, RTSTRCACHE hStrCache)
    238456    {
    239457        /* Load into local variables. If we failed during the load,
     
    241459        QMHashSet hashSet;
    242460        QMMessageArray messageArray;
     461        QMByteArray pluralRules;
    243462
    244463        stream.checkMagic();
     
    255474            {
    256475                case Messages:
    257                     parseMessages(stream, &hashSet, &messageArray, sLen);
     476                    parseMessages(stream, hStrCache, &hashSet, &messageArray, sLen);
    258477                    break;
    259478                case Hashes:
    260479                    /* Only get size information to speed-up vector filling
    261480                     * if Hashes section goes in the file before Message section */
    262                     m_messageArray.reserve(sLen >> 3);
    263                     RT_FALL_THRU();
    264                 case Context:
     481                    if (messageArray.empty())
     482                        messageArray.reserve(sLen >> 3);
     483                    stream.seek(sLen);
     484                    break;
     485                case NumerusRules:
     486                {
     487                    pluralRules.resize(sLen);
     488                    uint32_t cbSize = stream.read((char *)&pluralRules[0], sLen);
     489                    if (cbSize < sLen)
     490                        throw QMException("Incorrect section size");
     491                    if (!checkPlural(pluralRules))
     492                        pluralRules.erase(pluralRules.begin(), pluralRules.end());
     493                    break;
     494                }
     495                case Contexts:
     496                case Dependencies:
     497                case Language:
    265498                    stream.seek(sLen);
    266499                    break;
     
    269502            }
    270503        }
     504
    271505        /* Store the data into member variables.
    272506         * The following functions never generate exceptions */
    273507        m_hashSet.swap(hashSet);
    274508        m_messageArray.swap(messageArray);
     509        m_pluralRules.swap(pluralRules);
    275510    }
    276511
     
    280515    enum SectionType
    281516    {
    282         Hashes   = 0x42,
    283         Messages = 0x69,
    284         Contexts = 0x2f
     517        Contexts     = 0x2f,
     518        Hashes       = 0x42,
     519        Messages     = 0x69,
     520        NumerusRules = 0x88,
     521        Dependencies = 0x96,
     522        Language     = 0xa7
    285523    };
    286524
     
    291529        Translation  = 3,
    292530        Context16    = 4,
    293         Hash         = 5,
     531        Obsolete1    = 5,  /**< was Hash */
    294532        SourceText   = 6,
    295533        Context      = 7,
     
    298536
    299537    /* Read messages from the stream. */
    300     static void parseMessages(QMBytesStream &stream, QMHashSet * const hashSet, QMMessageArray * const messageArray, size_t cbSize)
     538    static void parseMessages(QMBytesStream &stream, RTSTRCACHE hStrCache, QMHashSet * const hashSet,
     539                              QMMessageArray * const messageArray, size_t cbSize)
    301540    {
    302541        stream.setEnd(stream.tellPos() + cbSize);
     
    304543        while (!stream.hasFinished())
    305544        {
    306             QMMessage message;
    307             HashOffset hashOffs;
    308 
    309             parseMessageRecord(stream, &message);
    310             if (!message.hash)
    311                 message.hash = calculateHash(message.strSource.c_str(), message.strComment.c_str());
    312 
    313             hashOffs.hash = message.hash;
    314             hashOffs.offset = cMessage++;
    315 
    316             hashSet->insert(hashOffs);
    317             messageArray->push_back(message);
     545            /* Process the record. Skip anything that doesn't have a source
     546               string or any valid translations.  Using C++ strings for temporary
     547               storage here, as we don't want to pollute the cache we bogus strings
     548               in case of duplicate sub-records or invalid records. */
     549            QMMessageParse ParsedMsg;
     550            parseMessageRecord(stream, &ParsedMsg);
     551            if (   ParsedMsg.astrTranslations.size() > 0
     552                && ParsedMsg.strSource.isNotEmpty())
     553            {
     554                /* Copy the strings over into the string cache and a hashed QMMessage,
     555                   before adding it to the result. */
     556                QMMessage HashedMsg(hStrCache, ParsedMsg);
     557                hashSet->insert(HashOffset(HashedMsg.hash, cMessage++));
     558                messageArray->push_back(HashedMsg);
     559
     560            }
     561            /*else: wtf? */
    318562        }
    319563        stream.setEnd();
     
    321565
    322566    /* Parse one message from the stream */
    323     static void parseMessageRecord(QMBytesStream &stream, QMMessage * const message)
     567    static void parseMessageRecord(QMBytesStream &stream, QMMessageParse * const message)
    324568    {
    325569        while (!stream.hasFinished())
     
    336580                    break;
    337581                case Translation:
    338                 {
    339                     com::Utf8Str str = stream.readUtf16String();
    340                     message->strTranslation.swap(str);
    341                     break;
    342                 }
    343                 case Hash:
    344                     message->hash = stream.read32();
     582                    message->astrTranslations.push_back(stream.readUtf16String());
    345583                    break;
    346584
    347585                case SourceText:
    348                 {
    349                     com::Utf8Str str = stream.readString();
    350                     message->strSource.swap(str);
    351                     break;
    352                 }
     586                    message->strSource = stream.readString();
     587                    break;
    353588
    354589                case Context:
    355                 {
    356                     com::Utf8Str str = stream.readString();
    357                     message->strContext.swap(str);
    358                     break;
    359                 }
     590                    message->strContext = stream.readString();
     591                    break;
    360592
    361593                case Comment:
    362                 {
    363                     com::Utf8Str str = stream.readString();
    364                     message->strComment.swap(str);
    365                     break;
    366                 }
     594                    message->strComment = stream.readString();
     595                    break;
    367596
    368597                default:
    369                     /* Ignore unknown block */
    370                     LogRel(("QMTranslator::parseMessageRecord(): Unkown message block %x\n", type));
     598                    /* Ignore unknown/obsolete block */
     599                    LogRel(("QMTranslator::parseMessageRecord(): Unknown/obsolete message block %x\n", type));
    371600                    break;
    372601            }
    373602        }
    374603    }
    375 
    376     /* Defines the so called `hashpjw' function by P.J. Weinberger
    377        [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
    378        1986, 1987 Bell Telephone Laboratories, Inc.]   */
    379     static uint32_t calculateHash(const char *pszStr1, const char *pszStr2 = 0)
    380     {
    381         uint32_t hash = 0, g;
    382 
    383         for (const char *pszStr = pszStr1; pszStr != pszStr2; pszStr = pszStr2)
    384             for (; pszStr && *pszStr; pszStr++)
    385             {
    386                 hash = (hash << 4) + static_cast<uint8_t>(*pszStr);
    387 
    388                 if ((g = hash & 0xf0000000ul) != 0)
    389                 {
    390                     hash ^= g >> 24;
    391                     hash ^= g;
    392                 }
    393             }
    394 
    395         return (hash != 0 ? hash : 1);
    396     }
    397604};
    398605
    399606/* Inteface functions implementation */
    400 QMTranslator::QMTranslator() : _impl(new QMTranslator_Impl) {}
    401 
    402 QMTranslator::~QMTranslator() { delete _impl; }
    403 
    404 const char *QMTranslator::translate(const char *pszContext, const char *pszSource, const char *pszDisamb) const throw()
     607QMTranslator::QMTranslator() : m_impl(new QMTranslator_Impl) {}
     608
     609QMTranslator::~QMTranslator() { delete m_impl; }
     610
     611const char *QMTranslator::translate(const char *pszContext, const char *pszSource,
     612                                    const char *pszDisamb, const int aNum) const throw()
    405613{
    406     return _impl->translate(pszContext, pszSource, pszDisamb);
     614    return m_impl->translate(pszContext, pszSource, pszDisamb, aNum);
    407615}
    408616
    409 /* The function is noexcept for now but it may be changed
    410  * to throw exceptions if required to catch them in another
    411  * place. */
    412 int QMTranslator::load(const char *pszFilename) throw()
     617int QMTranslator::load(const char *pszFilename, RTSTRCACHE hStrCache) RT_NOEXCEPT
    413618{
    414619    /* To free safely the file in case of exception */
     
    437642        {
    438643            QMBytesStream stream(loader.data, loader.cbSize);
    439             _impl->load(stream);
     644            m_impl->load(stream, hStrCache);
    440645        }
    441646        return loader.rc;
  • trunk/src/VBox/Main/src-all/TextScript.cpp

    r82968 r90828  
    5353    }
    5454    else
    55         hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc);
     55        hrc = mpSetError->setErrorVrc(vrc, tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc);
    5656    return hrc;
    5757}
     
    9494                }
    9595
    96                 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc);
     96                hrc = mpSetError->setErrorVrc(vrc, tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc);
    9797            }
    9898            else
    99                 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error reading '%s': %Rrc"), pszFilename, vrc);
     99                hrc = mpSetError->setErrorVrc(vrc, tr("Error reading '%s': %Rrc"), pszFilename, vrc);
    100100            mStrScriptFullContent.setNull();
    101101        }
    102102        else
    103             hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to allocate memory (%'RU64 bytes) for '%s'"),
     103            hrc = mpSetError->setErrorVrc(vrc, tr("Failed to allocate memory (%'RU64 bytes) for '%s'"),
    104104                                          cbFile, pszFilename);
    105105    }
    106106    else if (RT_SUCCESS(vrc))
    107         hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG,
    108                                       mpSetError->tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile);
     107        hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG, tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile);
    109108    else
    110         hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("RTVfsFileQuerySize failed (%Rrc)"), vrc);
     109        hrc = mpSetError->setErrorVrc(vrc, tr("RTVfsFileQuerySize failed (%Rrc)"), vrc);
    111110    return hrc;
    112111}
     
    179178            RTFileClose(hFile);
    180179            RTFileDelete(pszFilename);
    181             hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc);
     180            hrc = mpSetError->setErrorVrc(vrc, tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc);
    182181        }
    183182        else
    184             hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);
     183            hrc = mpSetError->setErrorVrc(vrc, tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);
    185184    }
    186185    return hrc;
  • trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp

    r83787 r90828  
    3434#include "AutoCaller.h"
    3535#include "VirtualBoxErrorInfoImpl.h"
     36#include "VirtualBoxTranslator.h"
    3637#include "Global.h"
    3738#include "LoggingNew.h"
     
    226227    catch (const RTCError &err)      // includes all XML exceptions
    227228    {
    228         return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
    229                                 Utf8StrFmt(tr("%s.\n%s[%d] (%s)"),
    230                                            err.what(),
    231                                            pszFile, iLine, pszFunction).c_str(),
    232                                 false /* aWarning */,
    233                                 true /* aLogIt */);
     229        return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
     230                                 false /* aWarning */,
     231                                 true /* aLogIt */,
     232                                 0 /* aResultDetail */,
     233                                 tr("%s.\n%s[%d] (%s)"),
     234                                 err.what(), pszFile, iLine, pszFunction);
    234235    }
    235236    catch (const std::exception &err)
    236237    {
    237         return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
    238                                 Utf8StrFmt(tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),
    239                                            err.what(), typeid(err).name(),
    240                                            pszFile, iLine, pszFunction).c_str(),
    241                                 false /* aWarning */,
    242                                 true /* aLogIt */);
     238        return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
     239                                 false /* aWarning */,
     240                                 true /* aLogIt */,
     241                                 0 /* aResultDetail */,
     242                                 tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),
     243                                 err.what(), typeid(err).name(), pszFile, iLine, pszFunction);
    243244    }
    244245    catch (...)
    245246    {
    246         return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
    247                                 Utf8StrFmt(tr("Unknown exception\n%s[%d] (%s)"),
    248                                            pszFile, iLine, pszFunction).c_str(),
    249                                 false /* aWarning */,
    250                                 true /* aLogIt */);
     247        return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
     248                                 false /* aWarning */,
     249                                 true /* aLogIt */,
     250                                 0 /* aResultDetail */,
     251                                 tr("Unknown exception\n%s[%d] (%s)"),
     252                                 pszFile, iLine, pszFunction);
    251253    }
    252254
     
    257259#endif
    258260}
     261
    259262
    260263/**
     
    266269 *  than an error.
    267270 *
     271 *  @param aResultCode
     272 *  @param aIID
     273 *  @param aComponent
     274 *  @param aWarning
     275 *  @param aLogIt
     276 *  @param aResultDetail
     277 *  @param aText
     278 */
     279/* static */
     280HRESULT VirtualBoxBase::setErrorInternalF(HRESULT aResultCode,
     281                                          const GUID &aIID,
     282                                          const char *aComponent,
     283                                          bool aWarning,
     284                                          bool aLogIt,
     285                                          LONG aResultDetail,
     286                                          const char *aText, ...)
     287{
     288    va_list va;
     289    va_start(va, aText);
     290    HRESULT hres = setErrorInternalV(aResultCode, aIID, aComponent, aText, va,
     291                                     aWarning, aLogIt, aResultDetail);
     292    va_end(va);
     293    return hres;
     294}
     295
     296/**
     297 *  Sets error info for the current thread. This is an internal function that
     298 *  gets eventually called by all public variants.  If @a aWarning is
     299 *  @c true, then the highest (31) bit in the @a aResultCode value which
     300 *  indicates the error severity is reset to zero to make sure the receiver will
     301 *  recognize that the created error info object represents a warning rather
     302 *  than an error.
     303 *
    268304 *  @param  aResultCode
    269305 *  @param  aIID
    270306 *  @param  pcszComponent
    271307 *  @param  aText
     308 *  @param  va
    272309 *  @param  aWarning
    273310 *  @param  aLogIt
     
    275312 */
    276313/* static */
    277 HRESULT VirtualBoxBase::setErrorInternal(HRESULT aResultCode,
    278                                          const GUID &aIID,
    279                                          const char *pcszComponent,
    280                                          Utf8Str aText,
    281                                          bool aWarning,
    282                                          bool aLogIt,
    283                                          LONG aResultDetail /* = 0*/)
     314HRESULT VirtualBoxBase::setErrorInternalV(HRESULT aResultCode,
     315                                          const GUID &aIID,
     316                                          const char *aComponent,
     317                                          const char *aText,
     318                                          va_list aArgs,
     319                                          bool aWarning,
     320                                          bool aLogIt,
     321                                          LONG aResultDetail /* = 0*/)
    284322{
    285323    /* whether multi-error mode is turned on */
    286324    bool preserve = MultiResult::isMultiEnabled();
    287325
     326    com::Utf8Str strText;
    288327    if (aLogIt)
    289         LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%s}, preserve=%RTbool aResultDetail=%d\n",
     328    {
     329        strText = trSource(aText);
     330        va_list va2;
     331        va_copy(va2, aArgs);
     332        LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%N}, preserve=%RTbool aResultDetail=%d\n",
    290333                aWarning ? "WARNING" : "ERROR",
    291334                aResultCode,
    292335                aResultCode,
    293336                &aIID,
    294                 pcszComponent,
    295                 aText.c_str(),
     337                aComponent,
     338                strText.c_str(),
     339                &va2,
    296340                preserve,
    297341                aResultDetail));
     342        va_end(va2);
     343    }
    298344
    299345    /* these are mandatory, others -- not */
     
    308354    HRESULT rc = S_OK;
    309355
    310     if (aText.isEmpty())
     356    if (aText == NULL || aText[0] == '\0')
    311357    {
    312358        /* Some default info */
    313359        switch (aResultCode)
    314360        {
    315             case E_INVALIDARG:                 aText = "A parameter has an invalid value"; break;
    316             case E_POINTER:                    aText = "A parameter is an invalid pointer"; break;
    317             case E_UNEXPECTED:                 aText = "The result of the operation is unexpected"; break;
    318             case E_ACCESSDENIED:               aText = "The access to an object is not allowed"; break;
    319             case E_OUTOFMEMORY:                aText = "The allocation of new memory failed"; break;
    320             case E_NOTIMPL:                    aText = "The requested operation is not implemented"; break;
    321             case E_NOINTERFACE:                aText = "The requested interface is not implemented"; break;
    322             case E_FAIL:                       aText = "A general error occurred"; break;
    323             case E_ABORT:                      aText = "The operation was canceled"; break;
    324             case VBOX_E_OBJECT_NOT_FOUND:      aText = "Object corresponding to the supplied arguments does not exist"; break;
    325             case VBOX_E_INVALID_VM_STATE:      aText = "Current virtual machine state prevents the operation"; break;
    326             case VBOX_E_VM_ERROR:              aText = "Virtual machine error occurred attempting the operation"; break;
    327             case VBOX_E_FILE_ERROR:            aText = "File not accessible or erroneous file contents"; break;
    328             case VBOX_E_IPRT_ERROR:            aText = "Runtime subsystem error"; break;
    329             case VBOX_E_PDM_ERROR:             aText = "Pluggable Device Manager error"; break;
    330             case VBOX_E_INVALID_OBJECT_STATE:  aText = "Current object state prohibits operation"; break;
    331             case VBOX_E_HOST_ERROR:            aText = "Host operating system related error"; break;
    332             case VBOX_E_NOT_SUPPORTED:         aText = "Requested operation is not supported"; break;
    333             case VBOX_E_XML_ERROR:             aText = "Invalid XML found"; break;
    334             case VBOX_E_INVALID_SESSION_STATE: aText = "Current session state prohibits operation"; break;
    335             case VBOX_E_OBJECT_IN_USE:         aText = "Object being in use prohibits operation"; break;
    336             case VBOX_E_PASSWORD_INCORRECT:    aText = "Incorrect password provided"; break;
    337             default:                           aText = "Unknown error"; break;
    338         }
     361            case E_INVALIDARG:                 strText = "A parameter has an invalid value"; break;
     362            case E_POINTER:                    strText = "A parameter is an invalid pointer"; break;
     363            case E_UNEXPECTED:                 strText = "The result of the operation is unexpected"; break;
     364            case E_ACCESSDENIED:               strText = "The access to an object is not allowed"; break;
     365            case E_OUTOFMEMORY:                strText = "The allocation of new memory failed"; break;
     366            case E_NOTIMPL:                    strText = "The requested operation is not implemented"; break;
     367            case E_NOINTERFACE:                strText = "The requested interface is not implemented"; break;
     368            case E_FAIL:                       strText = "A general error occurred"; break;
     369            case E_ABORT:                      strText = "The operation was canceled"; break;
     370            case VBOX_E_OBJECT_NOT_FOUND:      strText = "Object corresponding to the supplied arguments does not exist"; break;
     371            case VBOX_E_INVALID_VM_STATE:      strText = "Current virtual machine state prevents the operation"; break;
     372            case VBOX_E_VM_ERROR:              strText = "Virtual machine error occurred attempting the operation"; break;
     373            case VBOX_E_FILE_ERROR:            strText = "File not accessible or erroneous file contents"; break;
     374            case VBOX_E_IPRT_ERROR:            strText = "Runtime subsystem error"; break;
     375            case VBOX_E_PDM_ERROR:             strText = "Pluggable Device Manager error"; break;
     376            case VBOX_E_INVALID_OBJECT_STATE:  strText = "Current object state prohibits operation"; break;
     377            case VBOX_E_HOST_ERROR:            strText = "Host operating system related error"; break;
     378            case VBOX_E_NOT_SUPPORTED:         strText = "Requested operation is not supported"; break;
     379            case VBOX_E_XML_ERROR:             strText = "Invalid XML found"; break;
     380            case VBOX_E_INVALID_SESSION_STATE: strText = "Current session state prohibits operation"; break;
     381            case VBOX_E_OBJECT_IN_USE:         strText = "Object being in use prohibits operation"; break;
     382            case VBOX_E_PASSWORD_INCORRECT:    strText = "Incorrect password provided"; break;
     383            default:                           strText = "Unknown error"; break;
     384        }
     385    }
     386    else
     387    {
     388        va_list va2;
     389        va_copy(va2, aArgs);
     390        strText = com::Utf8StrFmt("%N", aText, &va2);
     391        va_end(va2);
    339392    }
    340393
     
    373426
    374427        /* set the current error info and preserve the previous one if any */
    375         rc = info->initEx(aResultCode, aResultDetail, aIID, pcszComponent, aText, curInfo);
     428        rc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, strText, curInfo);
    376429        if (FAILED(rc)) break;
    377430
     
    417470
    418471            /* set the current error info and preserve the previous one if any */
    419             rc = info->initEx(aResultCode, aResultDetail, aIID, pcszComponent, Bstr(aText), curInfo);
     472            rc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, Bstr(strText), curInfo);
    420473            if (FAILED(rc)) break;
    421474
     
    459512HRESULT VirtualBoxBase::setError(HRESULT aResultCode)
    460513{
    461     return setErrorInternal(aResultCode,
    462                             this->getClassIID(),
    463                             this->getComponentName(),
    464                             "",
    465                             false /* aWarning */,
    466                             true /* aLogIt */);
     514    return setErrorInternalF(aResultCode,
     515                             this->getClassIID(),
     516                             this->getComponentName(),
     517                             false /* aWarning */,
     518                             true /* aLogIt */,
     519                             0 /* aResultDetail */,
     520                             NULL);
    467521}
    468522
     
    480534    va_list args;
    481535    va_start(args, pcsz);
    482     HRESULT rc = setErrorInternal(aResultCode,
    483                                   this->getClassIID(),
    484                                   this->getComponentName(),
    485                                   Utf8Str(pcsz, args),
    486                                   false /* aWarning */,
    487                                   true /* aLogIt */);
     536    HRESULT rc = setErrorInternalV(aResultCode,
     537                                   this->getClassIID(),
     538                                   this->getComponentName(),
     539                                   pcsz, args,
     540                                   false /* aWarning */,
     541                                   true /* aLogIt */);
    488542    va_end(args);
    489543    return rc;
     
    628682HRESULT VirtualBoxBase::setErrorVrc(int vrc)
    629683{
    630     return setErrorInternal(Global::vboxStatusCodeToCOM(vrc),
    631                             this->getClassIID(),
    632                             this->getComponentName(),
    633                             Utf8StrFmt("%Rrc", vrc),
    634                             false /* aWarning */,
    635                             true /* aLogIt */,
    636                             vrc /* aResultDetail */);
     684    return setErrorInternalF(Global::vboxStatusCodeToCOM(vrc),
     685                             this->getClassIID(),
     686                             this->getComponentName(),
     687                             false /* aWarning */,
     688                             true /* aLogIt */,
     689                             vrc /* aResultDetail */,
     690                             Utf8StrFmt("%Rrc", vrc).c_str());
    637691}
    638692
     
    651705    va_list va;
    652706    va_start(va, pcszMsgFmt);
    653     HRESULT hrc = setErrorInternal(Global::vboxStatusCodeToCOM(vrc),
    654                                    this->getClassIID(),
    655                                    this->getComponentName(),
    656                                    Utf8Str(pcszMsgFmt, va),
    657                                    false /* aWarning */,
    658                                    true /* aLogIt */,
    659                                    vrc /* aResultDetail */);
     707    HRESULT hrc = setErrorInternalV(Global::vboxStatusCodeToCOM(vrc),
     708                                    this->getClassIID(),
     709                                    this->getComponentName(),
     710                                    pcszMsgFmt, va,
     711                                    false /* aWarning */,
     712                                    true /* aLogIt */,
     713                                    vrc /* aResultDetail */);
    660714    va_end(va);
    661715    return hrc;
     
    676730HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc)
    677731{
    678     return setErrorInternal(hrc,
    679                             this->getClassIID(),
    680                             this->getComponentName(),
    681                             Utf8StrFmt("%Rrc", vrc),
    682                             false /* aWarning */,
    683                             true /* aLogIt */,
    684                             vrc /* aResultDetail */);
     732    return setErrorInternalF(hrc,
     733                             this->getClassIID(),
     734                             this->getComponentName(),
     735                             false /* aWarning */,
     736                             true /* aLogIt */,
     737                             vrc /* aResultDetail */,
     738                             Utf8StrFmt("%Rrc", vrc).c_str());
    685739}
    686740
     
    703757    va_list va;
    704758    va_start(va, pcszMsgFmt);
    705     hrc = setErrorInternal(hrc,
    706                            this->getClassIID(),
    707                            this->getComponentName(),
    708                            Utf8Str(pcszMsgFmt, va),
    709                            false /* aWarning */,
    710                            true /* aLogIt */,
    711                            vrc /* aResultDetail */);
     759    hrc = setErrorInternalV(hrc,
     760                            this->getClassIID(),
     761                            this->getComponentName(),
     762                            pcszMsgFmt, va,
     763                            false /* aWarning */,
     764                            true /* aLogIt */,
     765                            vrc /* aResultDetail */);
    712766    va_end(va);
    713767    return hrc;
     
    724778    va_list args;
    725779    va_start(args, pcsz);
    726     HRESULT rc = setErrorInternal(aResultCode,
    727                                   this->getClassIID(),
    728                                   this->getComponentName(),
    729                                   Utf8Str(pcsz, args),
    730                                   true /* aWarning */,
    731                                   true /* aLogIt */);
     780    HRESULT rc = setErrorInternalV(aResultCode,
     781                                   this->getClassIID(),
     782                                   this->getComponentName(),
     783                                   pcsz, args,
     784                                   true /* aWarning */,
     785                                   true /* aLogIt */);
    732786    va_end(args);
    733787    return rc;
     
    744798    va_list args;
    745799    va_start(args, pcsz);
    746     HRESULT rc = setErrorInternal(aResultCode,
    747                                   this->getClassIID(),
    748                                   this->getComponentName(),
    749                                   Utf8Str(pcsz, args),
    750                                   false /* aWarning */,
    751                                   false /* aLogIt */);
     800    HRESULT rc = setErrorInternalV(aResultCode,
     801                                   this->getClassIID(),
     802                                   this->getComponentName(),
     803                                   pcsz, args,
     804                                   false /* aWarning */,
     805                                   false /* aLogIt */);
    752806    va_end(args);
    753807    return rc;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette